1 /* 2 * Stabs debugging format 3 * 4 * Copyright (C) 2003-2007 Michael Urman 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE 19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * POSSIBILITY OF SUCH DAMAGE. 26 */ 27 #include <util.h> 28 29 #include <libyasm.h> 30 31 typedef enum { 32 N_UNDF = 0x00, /* Undefined */ 33 N_GSYM = 0x20, /* Global symbol */ 34 N_FNAME = 0x22, /* Function name (BSD Fortran) */ 35 N_FUN = 0x24, /* Function name or Text segment variable */ 36 N_STSYM = 0x26, /* Data segment file-scope variable */ 37 N_LCSYM = 0x28, /* BSS segment file-scope variable */ 38 N_MAIN = 0x2a, /* Name of main routine */ 39 N_ROSYM = 0x2c, /* Variable in .rodata section */ 40 N_PC = 0x30, /* Global symbol (Pascal) */ 41 N_SYMS = 0x32, /* Number of symbols (Ultrix V4.0) */ 42 N_NOMAP = 0x34, /* No DST map */ 43 N_OBJ = 0x38, /* Object file (Solaris2) */ 44 N_OPT = 0x3c, /* Debugger options (Solaris2) */ 45 N_RSYM = 0x40, /* Register variable */ 46 N_M2C = 0x42, /* Modula-2 compilation unit */ 47 N_SLINE = 0x44, /* Line numbers in .text segment */ 48 N_DSLINE = 0x46, /* Line numbers in .data segment */ 49 N_BSLINE = 0x48, /* Line numbers in .bss segment */ 50 N_BROWS = 0x48, /* Source code .cb file's path */ 51 N_DEFD = 0x4a, /* GNU Modula-2 definition module dependency */ 52 N_FLINE = 0x4c, /* Function start/body/end line numbers (Solaris2) */ 53 N_EHDECL = 0x50, /* GNU C++ exception variable */ 54 N_MOD2 = 0x50, /* Modula2 info for imc (Ultrix V4.0) */ 55 N_CATCH = 0x54, /* GNU C++ catch clause */ 56 N_SSYM = 0x60, /* Structure or union element */ 57 N_ENDM = 0x62, /* Last stab for module (Solaris2) */ 58 N_SO = 0x64, /* Path and name of source files */ 59 N_LSYM = 0x80, /* Stack variable */ 60 N_BINCL = 0x84, /* Beginning of include file */ 61 N_SOL = 0x84, /* Name of include file */ 62 N_PSYM = 0xa0, /* Parameter variable */ 63 N_EINCL = 0xa2, /* End of include file */ 64 N_ENTRY = 0xa4, /* Alternate entry point */ 65 N_LBRAC = 0xc0, /* Beginning of lexical block */ 66 N_EXCL = 0xc2, /* Placeholder for a deleted include file */ 67 N_SCOPE = 0xc4, /* Modula 2 scope info (Sun) */ 68 N_RBRAC = 0xe0, /* End of lexical block */ 69 N_BCOMM = 0xe2, /* Begin named common block */ 70 N_ECOMM = 0xe4, /* End named common block */ 71 N_ECOML = 0xe8, /* Member of common block */ 72 N_WITH = 0xea, /* Pascal with statement: type,,0,0,offset (Solaris2) */ 73 N_NBTEXT = 0xf0, /* Gould non-base registers */ 74 N_NBDATA = 0xf2, /* Gould non-base registers */ 75 N_NBBSS = 0xf4, /* Gould non-base registers */ 76 N_NBSTS = 0xf6, /* Gould non-base registers */ 77 N_NBLCS = 0xf8 /* Gould non-base registers */ 78 } stabs_stab_type; 79 80 typedef struct yasm_dbgfmt_stabs { 81 yasm_dbgfmt_base dbgfmt; /* base structure */ 82 } yasm_dbgfmt_stabs; 83 84 typedef struct { 85 unsigned long lastline; /* track line and file of bytecodes */ 86 unsigned long curline; 87 const char *lastfile; 88 const char *curfile; 89 90 unsigned int stablen; /* size of a stab for current machine */ 91 unsigned long stabcount; /* count stored stabs; doesn't include first */ 92 93 yasm_section *stab; /* sections to which stabs, stabstrs appended */ 94 yasm_section *stabstr; 95 96 yasm_bytecode *basebc; /* base bytecode from which to track SLINEs */ 97 98 yasm_object *object; 99 yasm_linemap *linemap; 100 yasm_errwarns *errwarns; 101 } stabs_info; 102 103 typedef struct { 104 /*@null@*/ yasm_bytecode *bcstr; /* bytecode in stabstr for string */ 105 stabs_stab_type type; /* stab type: N_* */ 106 unsigned char other; /* unused, but stored here anyway */ 107 unsigned short desc; /* description element of a stab */ 108 /*@null@*/ yasm_symrec *symvalue; /* value element needing relocation */ 109 /*@null@*/yasm_bytecode *bcvalue; /* relocated stab's bytecode */ 110 unsigned long value; /* fallthrough value if above NULL */ 111 } stabs_stab; 112 113 /* Bytecode callback function prototypes */ 114 115 static void stabs_bc_str_destroy(void *contents); 116 static void stabs_bc_str_print(const void *contents, FILE *f, int 117 indent_level); 118 static int stabs_bc_str_calc_len 119 (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data); 120 static int stabs_bc_str_tobytes 121 (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d, 122 yasm_output_value_func output_value, 123 /*@null@*/ yasm_output_reloc_func output_reloc); 124 125 static void stabs_bc_stab_destroy(void *contents); 126 static void stabs_bc_stab_print(const void *contents, FILE *f, int 127 indent_level); 128 static int stabs_bc_stab_calc_len 129 (yasm_bytecode *bc, yasm_bc_add_span_func add_span, void *add_span_data); 130 static int stabs_bc_stab_tobytes 131 (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d, 132 yasm_output_value_func output_value, 133 /*@null@*/ yasm_output_reloc_func output_reloc); 134 135 /* Bytecode callback structures */ 136 137 static const yasm_bytecode_callback stabs_bc_str_callback = { 138 stabs_bc_str_destroy, 139 stabs_bc_str_print, 140 yasm_bc_finalize_common, 141 NULL, 142 stabs_bc_str_calc_len, 143 yasm_bc_expand_common, 144 stabs_bc_str_tobytes, 145 0 146 }; 147 148 static const yasm_bytecode_callback stabs_bc_stab_callback = { 149 stabs_bc_stab_destroy, 150 stabs_bc_stab_print, 151 yasm_bc_finalize_common, 152 NULL, 153 stabs_bc_stab_calc_len, 154 yasm_bc_expand_common, 155 stabs_bc_stab_tobytes, 156 0 157 }; 158 159 yasm_dbgfmt_module yasm_stabs_LTX_dbgfmt; 160 161 162 static /*@null@*/ /*@only@*/ yasm_dbgfmt * 163 stabs_dbgfmt_create(yasm_object *object) 164 { 165 yasm_dbgfmt_stabs *dbgfmt_stabs = yasm_xmalloc(sizeof(yasm_dbgfmt_stabs)); 166 dbgfmt_stabs->dbgfmt.module = &yasm_stabs_LTX_dbgfmt; 167 return (yasm_dbgfmt *)dbgfmt_stabs; 168 } 169 170 static void 171 stabs_dbgfmt_destroy(/*@only@*/ yasm_dbgfmt *dbgfmt) 172 { 173 yasm_xfree(dbgfmt); 174 } 175 176 /* Create and add a new strtab-style string bytecode to a section, updating 177 * offset on insertion; no optimization necessary */ 178 /* Copies the string, so you must still free yours as normal */ 179 static yasm_bytecode * 180 stabs_dbgfmt_append_bcstr(yasm_section *sect, const char *str) 181 { 182 yasm_bytecode *bc; 183 184 bc = yasm_bc_create_common(&stabs_bc_str_callback, yasm__xstrdup(str), 0); 185 bc->len = (unsigned long)(strlen(str)+1); 186 bc->offset = yasm_bc_next_offset(yasm_section_bcs_last(sect)); 187 188 yasm_section_bcs_append(sect, bc); 189 190 return bc; 191 } 192 193 /* Create and add a new stab bytecode to a section, updating offset on 194 * insertion; no optimization necessary. */ 195 /* Requires a string bytecode, or NULL, for its string entry */ 196 static stabs_stab * 197 stabs_dbgfmt_append_stab(stabs_info *info, yasm_section *sect, 198 /*@null@*/ yasm_bytecode *bcstr, stabs_stab_type type, 199 unsigned long desc, /*@null@*/ yasm_symrec *symvalue, 200 /*@null@*/ yasm_bytecode *bcvalue, unsigned long value) 201 { 202 yasm_bytecode *bc; 203 stabs_stab *stab = yasm_xmalloc(sizeof(stabs_stab)); 204 205 stab->other = 0; 206 stab->bcstr = bcstr; 207 stab->type = type; 208 stab->desc = (unsigned short)desc; 209 stab->symvalue = symvalue; 210 stab->bcvalue = bcvalue; 211 stab->value = value; 212 213 bc = yasm_bc_create_common(&stabs_bc_stab_callback, stab, 214 bcvalue ? bcvalue->line : 0); 215 bc->len = info->stablen; 216 bc->offset = yasm_bc_next_offset(yasm_section_bcs_last(sect)); 217 218 yasm_section_bcs_append(sect, bc); 219 220 info->stabcount++; 221 return stab; 222 } 223 224 static void 225 stabs_dbgfmt_generate_n_fun(stabs_info *info, yasm_bytecode *bc) 226 { 227 /* check all syms at this bc for potential function syms */ 228 int bcsym; 229 for (bcsym=0; bc->symrecs && bc->symrecs[bcsym]; bcsym++) 230 { 231 char *str; 232 yasm_symrec *sym = bc->symrecs[bcsym]; 233 const char *name = yasm_symrec_get_name(sym); 234 235 /* best guess algorithm - ignore labels containing a . or $ */ 236 if (strchr(name, '.') || strchr(name, '$')) 237 continue; 238 239 /* if a function, update basebc, and output a funcname:F1 stab */ 240 info->basebc = bc; 241 242 str = yasm_xmalloc(strlen(name)+4); 243 strcpy(str, name); 244 strcat(str, ":F1"); 245 stabs_dbgfmt_append_stab(info, info->stab, 246 stabs_dbgfmt_append_bcstr(info->stabstr, str), 247 N_FUN, 0, sym, info->basebc, 0); 248 yasm_xfree(str); 249 break; 250 } 251 } 252 253 static int 254 stabs_dbgfmt_generate_bcs(yasm_bytecode *bc, void *d) 255 { 256 stabs_info *info = (stabs_info *)d; 257 yasm_linemap_lookup(info->linemap, bc->line, &info->curfile, 258 &info->curline); 259 260 /* check for new function */ 261 stabs_dbgfmt_generate_n_fun(info, bc); 262 263 if (info->lastfile != info->curfile) { 264 info->lastline = 0; /* new file, so line changes */ 265 /*stabs_dbgfmt_append_stab(info, info->stab, 266 stabs_dbgfmt_append_bcstr(info->stabstr, info->curfile), 267 N_SOL, 0, NULL, bc, 0);*/ 268 } 269 270 /* output new line stabs if there's a basebc (known function) */ 271 if (info->basebc != NULL && info->curline != info->lastline) { 272 info->lastline = bc->line; 273 stabs_dbgfmt_append_stab(info, info->stab, NULL, N_SLINE, 274 info->curline, NULL, NULL, 275 bc->offset - info->basebc->offset); 276 } 277 278 info->lastline = info->curline; 279 info->lastfile = info->curfile; 280 281 return 0; 282 } 283 284 static int 285 stabs_dbgfmt_generate_sections(yasm_section *sect, /*@null@*/ void *d) 286 { 287 stabs_info *info = (stabs_info *)d; 288 const char *sectname=yasm_section_get_name(sect); 289 290 /* each section has a different base symbol */ 291 info->basebc = NULL; 292 293 /* handle first (pseudo) bc separately */ 294 stabs_dbgfmt_generate_n_fun(d, yasm_section_bcs_first(sect)); 295 296 yasm_section_bcs_traverse(sect, info->errwarns, d, 297 stabs_dbgfmt_generate_bcs); 298 299 if (yasm__strcasecmp(sectname, ".text")==0) { 300 /* Close out last function by appending a null SO stab after last bc */ 301 yasm_bytecode *bc = yasm_section_bcs_last(sect); 302 yasm_symrec *sym = 303 yasm_symtab_define_label(info->object->symtab, ".n_so", bc, 1, 304 bc->line); 305 stabs_dbgfmt_append_stab(info, info->stab, 0, N_SO, 0, sym, bc, 0); 306 } 307 308 return 1; 309 } 310 311 static void 312 stabs_dbgfmt_generate(yasm_object *object, yasm_linemap *linemap, 313 yasm_errwarns *errwarns) 314 { 315 stabs_info info; 316 int new; 317 yasm_bytecode *dbgbc; 318 stabs_stab *stab; 319 yasm_bytecode *filebc, *nullbc, *laststr, *firstbc; 320 yasm_symrec *firstsym; 321 yasm_section *stext; 322 323 /* Stablen is determined by arch/machine */ 324 if (yasm__strcasecmp(yasm_arch_keyword(object->arch), "x86") == 0) { 325 info.stablen = 12; 326 } 327 else /* unknown machine; generate nothing */ 328 return; 329 330 info.object = object; 331 info.linemap = linemap; 332 info.errwarns = errwarns; 333 info.lastline = 0; 334 info.stabcount = 0; 335 info.stab = yasm_object_get_general(object, ".stab", 4, 0, 0, &new, 0); 336 if (!new) { 337 yasm_bytecode *last = yasm_section_bcs_last(info.stab); 338 if (last == NULL) { 339 yasm_error_set(YASM_ERROR_GENERAL, 340 N_("stabs debugging conflicts with user-defined section .stab")); 341 yasm_errwarn_propagate(errwarns, 342 yasm_section_bcs_first(info.stab)->line); 343 } else { 344 yasm_warn_set(YASM_WARN_GENERAL, 345 N_("stabs debugging overrides empty section .stab")); 346 yasm_errwarn_propagate(errwarns, 0); 347 } 348 } 349 350 info.stabstr = 351 yasm_object_get_general(object, ".stabstr", 1, 0, 0, &new, 0); 352 if (!new) { 353 yasm_bytecode *last = yasm_section_bcs_last(info.stabstr); 354 if (last == NULL) { 355 yasm_error_set(YASM_ERROR_GENERAL, 356 N_("stabs debugging conflicts with user-defined section .stabstr")); 357 yasm_errwarn_propagate(errwarns, 358 yasm_section_bcs_first(info.stab)->line); 359 } else { 360 yasm_warn_set(YASM_WARN_GENERAL, 361 N_("stabs debugging overrides empty section .stabstr")); 362 yasm_errwarn_propagate(errwarns, 0); 363 } 364 } 365 366 /* initial pseudo-stab */ 367 stab = yasm_xmalloc(sizeof(stabs_stab)); 368 dbgbc = yasm_bc_create_common(&stabs_bc_stab_callback, stab, 0); 369 dbgbc->len = info.stablen; 370 dbgbc->offset = 0; 371 yasm_section_bcs_append(info.stab, dbgbc); 372 373 /* initial strtab bytecodes */ 374 nullbc = stabs_dbgfmt_append_bcstr(info.stabstr, ""); 375 filebc = stabs_dbgfmt_append_bcstr(info.stabstr, object->src_filename); 376 377 stext = yasm_object_find_general(object, ".text"); 378 firstsym = yasm_symtab_use(object->symtab, ".text", 0); 379 firstbc = yasm_section_bcs_first(stext); 380 /* N_SO file stab */ 381 stabs_dbgfmt_append_stab(&info, info.stab, filebc, N_SO, 0, 382 firstsym, firstbc, 0); 383 384 yasm_object_sections_traverse(object, (void *)&info, 385 stabs_dbgfmt_generate_sections); 386 387 /* fill initial pseudo-stab's fields */ 388 laststr = yasm_section_bcs_last(info.stabstr); 389 if (laststr == NULL) 390 yasm_internal_error(".stabstr has no entries"); 391 392 stab->bcvalue = NULL; 393 stab->symvalue = NULL; 394 stab->value = yasm_bc_next_offset(laststr); 395 stab->bcstr = filebc; 396 stab->type = N_UNDF; 397 stab->other = 0; 398 if (info.stabcount > 0xffff) { 399 yasm_warn_set(YASM_WARN_GENERAL, N_("over 65535 stabs")); 400 yasm_errwarn_propagate(errwarns, 0); 401 stab->desc = 0xffff; 402 } else 403 stab->desc = (unsigned short)info.stabcount; 404 } 405 406 static int 407 stabs_bc_stab_tobytes(yasm_bytecode *bc, unsigned char **bufp, 408 unsigned char *bufstart, void *d, 409 yasm_output_value_func output_value, 410 yasm_output_reloc_func output_reloc) 411 { 412 /* This entire function, essentially the core of rendering stabs to a file, 413 * needs to become endian aware. Size appears not to be an issue, as known 414 * 64-bit systems use truncated values in 32-bit fields. */ 415 416 const stabs_stab *stab = (const stabs_stab *)bc->contents; 417 unsigned char *buf = *bufp; 418 419 YASM_WRITE_32_L(buf, stab->bcstr ? stab->bcstr->offset : 0); 420 YASM_WRITE_8(buf, stab->type); 421 YASM_WRITE_8(buf, stab->other); 422 YASM_WRITE_16_L(buf, stab->desc); 423 424 if (stab->symvalue != NULL) { 425 bc->offset += 8; 426 output_reloc(stab->symvalue, bc, buf, 4, 32, 0, d); 427 bc->offset -= 8; 428 buf += 4; 429 } 430 else if (stab->bcvalue != NULL) { 431 YASM_WRITE_32_L(buf, stab->bcvalue->offset); 432 } 433 else { 434 YASM_WRITE_32_L(buf, stab->value); 435 } 436 437 *bufp = buf; 438 return 0; 439 } 440 441 static int 442 stabs_bc_str_tobytes(yasm_bytecode *bc, unsigned char **bufp, 443 unsigned char *bufstart, void *d, 444 yasm_output_value_func output_value, 445 yasm_output_reloc_func output_reloc) 446 { 447 const char *str = (const char *)bc->contents; 448 unsigned char *buf = *bufp; 449 450 strcpy((char *)buf, str); 451 buf += strlen(str)+1; 452 453 *bufp = buf; 454 return 0; 455 } 456 457 static void 458 stabs_bc_stab_destroy(void *contents) 459 { 460 yasm_xfree(contents); 461 } 462 463 static void 464 stabs_bc_str_destroy(void *contents) 465 { 466 yasm_xfree(contents); 467 } 468 469 static void 470 stabs_bc_stab_print(const void *contents, FILE *f, int indent_level) 471 { 472 const stabs_stab *stab = (const stabs_stab *)contents; 473 const char *str = ""; 474 fprintf(f, "%*s.stabs \"%s\", 0x%x, 0x%x, 0x%x, 0x%lx\n", 475 indent_level, "", str, stab->type, stab->other, stab->desc, 476 stab->bcvalue ? stab->bcvalue->offset : stab->value); 477 } 478 479 static void 480 stabs_bc_str_print(const void *contents, FILE *f, int indent_level) 481 { 482 fprintf(f, "%*s\"%s\"\n", indent_level, "", (const char *)contents); 483 } 484 485 static int 486 stabs_bc_stab_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, 487 void *add_span_data) 488 { 489 yasm_internal_error(N_("tried to resolve a stabs stab bytecode")); 490 /*@notreached@*/ 491 return 0; 492 } 493 494 static int 495 stabs_bc_str_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span, 496 void *add_span_data) 497 { 498 yasm_internal_error(N_("tried to resolve a stabs str bytecode")); 499 /*@notreached@*/ 500 return 0; 501 } 502 503 /* Define dbgfmt structure -- see dbgfmt.h for details */ 504 yasm_dbgfmt_module yasm_stabs_LTX_dbgfmt = { 505 "Stabs debugging format", 506 "stabs", 507 NULL, /* no directives */ 508 stabs_dbgfmt_create, 509 stabs_dbgfmt_destroy, 510 stabs_dbgfmt_generate 511 }; 512