1 /* $OpenBSD: dbm_dump.c,v 1.2 2016/08/30 22:20:03 schwarze Exp $ */ 2 /* 3 * Copyright (c) 2016 Ingo Schwarze <schwarze@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 * 17 * Function to dump an on-disk read-only mandoc database 18 * in diff(1)able format for debugging purposes. 19 */ 20 #include <err.h> 21 #include <regex.h> 22 #include <stdint.h> 23 #include <stdio.h> 24 #include <string.h> 25 26 #include "mansearch.h" 27 #include "dbm_map.h" 28 #include "dbm.h" 29 30 union ptr { 31 const char *c; 32 const int32_t *i; 33 }; 34 35 static void dump(void); 36 static const char *dump_macro(union ptr, int32_t); 37 static const char *dump_macros(union ptr); 38 static const char *dump_pages(union ptr); 39 static void dump_str(const char **); 40 static void dump_lst(const char **); 41 static void pchk(const char *, const char **, const char *, int); 42 43 44 int 45 main(int argc, char *argv[]) 46 { 47 if (argc != 2) 48 errx(1, "usage: dump filename"); 49 if (dbm_open(argv[1]) == -1) 50 err(1, "%s", argv[1]); 51 dump(); 52 dbm_close(); 53 return 0; 54 } 55 56 static void 57 dump(void) 58 { 59 union ptr p, macros, end; 60 61 p.i = dbm_getint(0); 62 printf("initial magic 0x%08x\n", be32toh(*p.i++)); 63 printf("version 0x%08x\n", be32toh(*p.i++)); 64 printf("macros offset 0x%08x\n", be32toh(*p.i)); 65 macros.i = dbm_get(*p.i++); 66 printf("end offset 0x%08x\n", be32toh(*p.i)); 67 end.i = dbm_get(*p.i++); 68 p.c = dump_pages(p); 69 pchk(macros.c, &p.c, "macros", 3); 70 p.c = dump_macros(p); 71 pchk(end.c, &p.c, "end", 0); 72 printf("final magic 0x%08x\n", be32toh(*p.i)); 73 } 74 75 static const char * 76 dump_pages(union ptr p) 77 { 78 const char *name0, *sect0, *arch0, *desc0, *file0; 79 const char *namep, *sectp, *archp, *descp, *filep; 80 int32_t i, npages; 81 82 npages = be32toh(*p.i++); 83 printf("page count %d\n", npages); 84 if (npages == 0) 85 return p.c; 86 namep = name0 = dbm_get(p.i[0]); 87 sectp = sect0 = dbm_get(p.i[1]); 88 archp = arch0 = p.i[2] == 0 ? NULL : dbm_get(p.i[2]); 89 descp = desc0 = dbm_get(p.i[3]); 90 filep = file0 = dbm_get(p.i[4]); 91 printf("=== PAGES ===\n"); 92 for (i = 0; i < npages; i++) { 93 pchk(dbm_get(*p.i++), &namep, "name", 0); 94 printf("page name "); 95 dump_lst(&namep); 96 pchk(dbm_get(*p.i++), §p, "sect", 0); 97 printf("page sect "); 98 dump_lst(§p); 99 if (*p.i++) { 100 if (arch0 == NULL) 101 archp = arch0 = dbm_get(p.i[-1]); 102 else 103 pchk(dbm_get(p.i[-1]), &archp, "arch", 0); 104 printf("page arch "); 105 dump_lst(&archp); 106 } 107 pchk(dbm_get(*p.i++), &descp, "desc", 0); 108 printf("page desc # "); 109 dump_str(&descp); 110 printf("\npage file "); 111 pchk(dbm_get(*p.i++), &filep, "file", 0); 112 if (filep == NULL) { 113 printf("# (NULL)\n"); 114 continue; 115 } 116 switch(*filep++) { 117 case 1: 118 printf("src "); 119 break; 120 case 2: 121 printf("cat "); 122 break; 123 default: 124 printf("UNKNOWN FORMAT %d ", filep[-1]); 125 break; 126 } 127 dump_lst(&filep); 128 } 129 printf("=== END OF PAGES ===\n"); 130 pchk(name0, &p.c, "name0", 0); 131 pchk(sect0, &namep, "sect0", 0); 132 if (arch0 != NULL) { 133 pchk(arch0, §p, "arch0", 0); 134 pchk(desc0, &archp, "desc0", 0); 135 } else 136 pchk(desc0, §p, "desc0", 0); 137 pchk(file0, &descp, "file0", 0); 138 return filep; 139 } 140 141 static const char * 142 dump_macros(union ptr p) 143 { 144 union ptr macro0, macrop; 145 int32_t i, nmacros; 146 147 nmacros = be32toh(*p.i++); 148 printf("macros count %d\n", nmacros); 149 if (nmacros == 0) 150 return p.c; 151 macrop.i = macro0.i = dbm_get(*p.i); 152 printf("=== MACROS ===\n"); 153 for (i = 0; i < nmacros; i++) { 154 pchk(dbm_get(*p.i++), ¯op.c, "macro", 0); 155 macrop.c = dump_macro(macrop, i); 156 } 157 printf("=== END OF MACROS ===\n"); 158 pchk(macro0.c, &p.c, "macro0", 0); 159 return macrop.c; 160 } 161 162 static const char * 163 dump_macro(union ptr p, int32_t im) 164 { 165 union ptr page0, pagep; 166 const char *val0, *valp; 167 int32_t i, nentries; 168 169 nentries = be32toh(*p.i++); 170 printf("macro %02d entry count %d\n", im, nentries); 171 if (nentries == 0) 172 return p.c; 173 valp = val0 = dbm_get(p.i[0]); 174 pagep.i = page0.i = dbm_get(p.i[1]); 175 printf("=== MACRO %02d ===\n", im); 176 for (i = 0; i < nentries; i++) { 177 pchk(dbm_get(*p.i++), &valp, "value", 0); 178 printf("macro %02d # ", im); 179 dump_str(&valp); 180 pchk(dbm_get(*p.i++), &pagep.c, "pages", 0); 181 while (*pagep.i++ != 0) 182 printf("# %s ", (char *)dbm_get( 183 *(int32_t *)dbm_get(pagep.i[-1])) + 1); 184 printf("\n"); 185 } 186 printf("=== END OF MACRO %02d ===\n", im); 187 pchk(val0, &p.c, "value0", 0); 188 pchk(page0.c, &valp, "page0", 3); 189 return pagep.c; 190 } 191 192 static void 193 dump_str(const char **cp) 194 { 195 if (*cp == NULL) { 196 printf("(NULL)"); 197 return; 198 } 199 if (**cp <= (char)NAME_MASK) { 200 putchar('['); 201 if (**cp & NAME_FILE) 202 putchar('f'); 203 if (**cp & NAME_HEAD) 204 putchar('h'); 205 if (**cp & NAME_FIRST) 206 putchar('1'); 207 if (**cp & NAME_TITLE) 208 putchar('t'); 209 if (**cp & NAME_SYN) 210 putchar('s'); 211 putchar(']'); 212 (*cp)++; 213 } 214 while (**cp != '\0') 215 putchar(*(*cp)++); 216 putchar(' '); 217 (*cp)++; 218 } 219 220 static void 221 dump_lst(const char **cp) 222 { 223 if (*cp == NULL) { 224 printf("# (NULL)\n"); 225 return; 226 } 227 while (**cp != '\0') { 228 printf("# "); 229 dump_str(cp); 230 } 231 (*cp)++; 232 printf("\n"); 233 } 234 235 static void 236 pchk(const char *want, const char **got, const char *name, int fuzz) 237 { 238 if (want == NULL) { 239 warnx("%s wants (NULL), ignoring", name); 240 return; 241 } 242 if (*got == NULL) 243 warnx("%s jumps from (NULL) to 0x%x", name, 244 be32toh(dbm_addr(want))); 245 else if (*got > want || *got + fuzz < want) 246 warnx("%s jumps from 0x%x to 0x%x", name, 247 be32toh(dbm_addr(*got)), be32toh(dbm_addr(want))); 248 *got = want; 249 } 250