1/* $OpenBSD: dbm_dump.c,v 1.3 2024/05/14 00:31:48 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 30union ptr { 31 const char *c; 32 const int32_t *i; 33}; 34 35static void dump(void); 36static const char *dump_macro(union ptr, int32_t); 37static const char *dump_macros(union ptr); 38static const char *dump_pages(union ptr); 39static void dump_str(const char **); 40static void dump_lst(const char **); 41static void pchk(const char *, const char **, const char *, int); 42 43 44int 45main(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 56static void 57dump(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 75static const char * 76dump_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 141static const char * 142dump_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 162static const char * 163dump_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 192static void 193dump_str(const char **cp) 194{ 195 if (*cp == NULL) { 196 printf("(NULL)"); 197 return; 198 } 199 if ((unsigned char)**cp <= 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 220static void 221dump_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 235static void 236pchk(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