|
|
1.1 ! root 1: /* Output GDB-format symbol table information from GNU compiler. ! 2: Copyright (C) 1987, 1988 Free Software Foundation, Inc. ! 3: ! 4: This file is part of GNU CC. ! 5: ! 6: GNU CC is distributed in the hope that it will be useful, ! 7: but WITHOUT ANY WARRANTY. No author or distributor ! 8: accepts responsibility to anyone for the consequences of using it ! 9: or for whether it serves any particular purpose or works at all, ! 10: unless he says so in writing. Refer to the GNU CC General Public ! 11: License for full details. ! 12: ! 13: Everyone is granted permission to copy, modify and redistribute ! 14: GNU CC, but only under the conditions described in the ! 15: GNU CC General Public License. A copy of this license is ! 16: supposed to have been given to you along with GNU CC so you ! 17: can know your rights and responsibilities. It should be in a ! 18: file named COPYING. Among other things, the copyright notice ! 19: and this notice must be preserved on all copies. */ ! 20: ! 21: ! 22: #include "config.h" ! 23: #include "tree.h" ! 24: #include "symseg.h" ! 25: #include "rtl.h" ! 26: #include "gdbfiles.h" ! 27: #include <stdio.h> ! 28: ! 29: /* Get N_SO from stab.h if we can expect the file to exist. */ ! 30: #ifndef NO_DBX_FORMAT ! 31: #include <stab.h> ! 32: #endif ! 33: ! 34: /* .stabs code for source file name. */ ! 35: #ifndef N_SO ! 36: #define N_SO 0x64 ! 37: #endif ! 38: ! 39: /* Unix maximum on file name length. Needed for getwd. */ ! 40: #define MAXNAMLEN 1024 ! 41: ! 42: /* Get the number to output for a reference to type TYPE. */ ! 43: #define TYPE_OUTPUT_ADDRESS(TYPE) \ ! 44: TYPE_SYMTAB_ADDRESS (TYPE_MAIN_VARIANT (TYPE)) ! 45: ! 46: /* Stream for writing symbol table file. */ ! 47: static FILE *symfile; ! 48: ! 49: /* Name of symbol table file. */ ! 50: static char *symfile_name; ! 51: ! 52: /* Stream for writing to assembler file. */ ! 53: static FILE *asmfile; ! 54: ! 55: /* Address for allocating space in symbol table file. ! 56: Changes in this variable are paired globally with writes to symfile, ! 57: but often we allocate many structures, advancing next_address, ! 58: before writing any of them. */ ! 59: static int next_address; ! 60: ! 61: /* Chain recording all the types that have been output, ! 62: giving the address-in-the-symseg of each one. */ ! 63: ! 64: struct typevec_elt ! 65: { ! 66: int address; ! 67: struct typevec_elt *next; ! 68: }; ! 69: ! 70: static struct typevec_elt *typevec; ! 71: ! 72: /* Number of types recorded so far in the chain. */ ! 73: ! 74: static int total_types; ! 75: ! 76: /* `blockvec' is a chain recording all the symbol-blocks that have been output, ! 77: giving the address-in-the-symseg of each one. */ ! 78: ! 79: struct blockvec_elt ! 80: { ! 81: int address; ! 82: struct blockvec_elt *next; ! 83: }; ! 84: ! 85: static struct blockvec_elt *blockvec; ! 86: ! 87: /* Number of blocks recorded so far in the chain. */ ! 88: ! 89: static int total_blocks; ! 90: ! 91: static void symout_range_bounds (); ! 92: static void symout_array_domain (); ! 93: static void symout_record_fields (); ! 94: static void symout_enum_values (); ! 95: static void symout_record_field_names (); ! 96: static void symout_enum_value_names (); ! 97: static int subrange_p (); ! 98: static void symout_strings_skip (); ! 99: static void symout_strings_print (); ! 100: ! 101: /* At the beginning of compilation, start writing the symbol table. ! 102: Initialize the type and block chain. ! 103: Also open and initialize the symseg file. */ ! 104: ! 105: void ! 106: symout_init (filename, asm_file, sourcename) ! 107: char *filename; ! 108: FILE *asm_file; ! 109: char *sourcename; ! 110: { ! 111: struct symbol_root buffer; ! 112: ! 113: #ifdef VMS ! 114: fatal ("Cannot write GDB debugging format on VMS"); ! 115: #endif ! 116: ! 117: asmfile = asm_file; ! 118: fprintf (asmfile, ".text 0\n.gdbbeg 0\n.gdbbeg 1\n"); ! 119: fprintf (asmfile, ! 120: "Ltext:\t.stabs \"%s\",%d,0,0,Ltext\n", ! 121: sourcename, N_SO); ! 122: fprintf (asmfile, ".data 0\nLdata:\n"); ! 123: ASM_OUTPUT_LOCAL (asmfile, "Lbss", 0); ! 124: fprintf (asmfile, ".gdbsym Ldata,%d\n", ! 125: (char *) &buffer.databeg - (char *) &buffer); ! 126: fprintf (asmfile, ".gdbsym Lbss,%d\n", ! 127: (char *) &buffer.bssbeg - (char *) &buffer); ! 128: ! 129: symfile = fopen (filename, "w"); ! 130: if (symfile == 0) ! 131: pfatal_with_name (symfile); ! 132: symfile_name = (char *) malloc (strlen (filename) + 1); ! 133: strcpy (symfile_name, filename); ! 134: ! 135: typevec = 0; ! 136: blockvec = 0; ! 137: total_types = 0; ! 138: total_blocks = 0; ! 139: ! 140: bzero (&buffer, sizeof buffer); ! 141: fwrite (&buffer, sizeof buffer, 1, symfile); ! 142: ! 143: next_address = sizeof buffer; ! 144: } ! 145: ! 146: /* Functions for outputting strings into the symbol table. ! 147: The string to be output is effectively the concatenation of ! 148: the two strings P1 and P2. Their lengths are given as S1 and S2. ! 149: If P1 or P2 is zero, that string is not used. ! 150: ! 151: A null character is output to terminate the string, ! 152: and it is followed by more nulls as padding to a word boundary. */ ! 153: ! 154: static void ! 155: symout_strings (p1, s1, p2, s2) ! 156: char *p1; ! 157: int s1; ! 158: char *p2; ! 159: int s2; ! 160: { ! 161: symout_strings_print (p1, s1, p2, s2); ! 162: symout_strings_skip (p1, s1, p2, s2); ! 163: } ! 164: ! 165: /* Like symout_strings but only output; do not update next_address. */ ! 166: ! 167: static void ! 168: symout_strings_print (p1, s1, p2, s2) ! 169: char *p1; ! 170: int s1; ! 171: char *p2; ! 172: int s2; ! 173: { ! 174: register int total; ! 175: ! 176: if (p1 && s1 == 0) ! 177: s1 = strlen (p1); ! 178: if (p2 && s2 == 0) ! 179: s2 = strlen (p2); ! 180: ! 181: if (p1) ! 182: fwrite (p1, s1, 1, symfile); ! 183: if (p2) ! 184: fwrite (p2, s2, 1, symfile); ! 185: putc (0, symfile); ! 186: ! 187: total = s1 + s2 + 1; ! 188: while (total % sizeof (int)) ! 189: { ! 190: putc (0, symfile); ! 191: total++; ! 192: } ! 193: } ! 194: ! 195: /* Like symout_strings but just update next_address; do not output. */ ! 196: ! 197: static void ! 198: symout_strings_skip (p1, s1, p2, s2) ! 199: char *p1; ! 200: int s1; ! 201: char *p2; ! 202: int s2; ! 203: { ! 204: register int total; ! 205: ! 206: if (p1 && s1 == 0) ! 207: s1 = strlen (p1); ! 208: if (p2 && s2 == 0) ! 209: s2 = strlen (p2); ! 210: ! 211: total = s1 + s2 + 1; ! 212: while (total % sizeof (int)) ! 213: total++; ! 214: ! 215: next_address += total; ! 216: } ! 217: ! 218: /* Call here to output a chain of types. ! 219: After each function, this is done first for the chain of permanent types ! 220: made during the function, and then for the chain of temporary types. ! 221: This must be done before outputting the symbols and blocks of the function. ! 222: ! 223: At the end of compilation, this is done for all the permanent types ! 224: made since the last function. ! 225: ! 226: Each permanent type is done once, at the beginning of the next function, ! 227: or at the end of the compilation if no functions follow. ! 228: Once a type has been processed here, its TYPE_SYMTAB_ADDRESS remains ! 229: set up. */ ! 230: ! 231: void ! 232: symout_types (types) ! 233: tree types; ! 234: { ! 235: struct typerec ! 236: { ! 237: int number; ! 238: int address; ! 239: int nfields; ! 240: int fields_address; ! 241: int name_address; ! 242: char *name; ! 243: char *name_prefix; ! 244: }; ! 245: ! 246: register int n_types, i; ! 247: register struct typerec *records; ! 248: register tree next; ! 249: struct type buffer; ! 250: ! 251: for (next = types, n_types = 0; ! 252: next; ! 253: next = TREE_CHAIN (next), n_types++); ! 254: ! 255: records = (struct typerec *) alloca (n_types * sizeof (struct typerec)); ! 256: ! 257: for (next = types, i = 0; ! 258: next; ! 259: next = TREE_CHAIN (next), i++) ! 260: { ! 261: register struct typevec_elt *velt ! 262: = (struct typevec_elt *) xmalloc (sizeof (struct typevec_elt)); ! 263: velt->next = typevec; ! 264: typevec = velt; ! 265: ! 266: total_types++; ! 267: ! 268: if (TYPE_NAME (next)) ! 269: { ! 270: records[i].name_address = next_address; ! 271: ! 272: if (TREE_CODE (TYPE_NAME (next)) == IDENTIFIER_NODE) ! 273: { ! 274: records[i].name = IDENTIFIER_POINTER (TYPE_NAME (next)); ! 275: switch (TREE_CODE (next)) ! 276: { ! 277: case RECORD_TYPE: ! 278: records[i].name_prefix = "struct "; ! 279: break; ! 280: ! 281: case UNION_TYPE: ! 282: records[i].name_prefix = "union "; ! 283: break; ! 284: ! 285: case ENUMERAL_TYPE: ! 286: records[i].name_prefix = "enum "; ! 287: break; ! 288: } ! 289: } ! 290: else ! 291: { ! 292: records[i].name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (next))); ! 293: records[i].name_prefix = 0; ! 294: } ! 295: symout_strings_skip (records[i].name_prefix, 0, ! 296: records[i].name, 0); ! 297: ! 298: } ! 299: else ! 300: { ! 301: records[i].name = 0; ! 302: records[i].name_address = 0; ! 303: records[i].name_prefix = 0; ! 304: } ! 305: ! 306: records[i].address = next_address; ! 307: TYPE_SYMTAB_ADDRESS (next) = next_address; ! 308: velt->address = next_address; ! 309: next_address += sizeof (struct type); ! 310: records[i].nfields = 0; ! 311: records[i].fields_address = 0; ! 312: switch (TREE_CODE (next)) ! 313: { ! 314: case ARRAY_TYPE: ! 315: records[i].nfields ! 316: = (TYPE_DOMAIN(next) ! 317: ? ! integer_zerop (TYPE_MIN_VALUE (TYPE_DOMAIN (next))) ! 318: : 0 ); ! 319: break; ! 320: ! 321: case INTEGER_TYPE: ! 322: if (subrange_p (next)) ! 323: buffer.nfields = 2; ! 324: break; ! 325: ! 326: case RECORD_TYPE: ! 327: case UNION_TYPE: ! 328: case ENUMERAL_TYPE: ! 329: records[i].nfields = list_length (TYPE_FIELDS (next)); ! 330: } ! 331: if (records[i].nfields) ! 332: records[i].fields_address = next_address; ! 333: next_address += records[i].nfields * sizeof (struct field); ! 334: } ! 335: ! 336: for (next = types, i = 0; ! 337: next; ! 338: next = TREE_CHAIN (next), i++) ! 339: { ! 340: if (records[i].name) ! 341: symout_strings_print (records[i].name_prefix, 0, ! 342: records[i].name, 0); ! 343: ! 344: if (TYPE_SIZE (next) == 0) ! 345: buffer.length = 0; ! 346: else ! 347: buffer.length ! 348: = (TREE_INT_CST_LOW (TYPE_SIZE (next)) ! 349: * TYPE_SIZE_UNIT (next) / BITS_PER_UNIT); ! 350: buffer.name = (char *) records[i].name_address; ! 351: buffer.target_type = (struct type *) (TREE_TYPE (next) ? TYPE_OUTPUT_ADDRESS (TREE_TYPE (next)) : 0); ! 352: ! 353: buffer.pointer_type = 0; ! 354: buffer.function_type = 0; ! 355: buffer.flags ! 356: = ((TREE_CODE (next) == INTEGER_TYPE || TREE_CODE (next) == ENUMERAL_TYPE) ! 357: && TREE_UNSIGNED (next)) ! 358: ? TYPE_FLAG_UNSIGNED : 0; ! 359: buffer.nfields = records[i].nfields; ! 360: buffer.fields = (struct field *) records[i].fields_address; ! 361: ! 362: switch (TREE_CODE (next)) ! 363: { ! 364: case INTEGER_TYPE: ! 365: buffer.code = TYPE_CODE_INT; ! 366: if (buffer.nfields) ! 367: buffer.code = TYPE_CODE_RANGE; ! 368: break; ! 369: ! 370: case REAL_TYPE: ! 371: buffer.code = TYPE_CODE_FLT; ! 372: break; ! 373: ! 374: case VOID_TYPE: ! 375: buffer.code = TYPE_CODE_VOID; ! 376: break; ! 377: ! 378: case POINTER_TYPE: ! 379: buffer.code = TYPE_CODE_PTR; ! 380: break; ! 381: ! 382: case ARRAY_TYPE: ! 383: if (buffer.nfields == 0) ! 384: buffer.code = TYPE_CODE_ARRAY; ! 385: else ! 386: buffer.code = TYPE_CODE_PASCAL_ARRAY; ! 387: break; ! 388: ! 389: case RECORD_TYPE: ! 390: buffer.code = TYPE_CODE_STRUCT; ! 391: break; ! 392: ! 393: case UNION_TYPE: ! 394: buffer.code = TYPE_CODE_UNION; ! 395: break; ! 396: ! 397: case FUNCTION_TYPE: ! 398: buffer.code = TYPE_CODE_FUNC; ! 399: break; ! 400: ! 401: case ENUMERAL_TYPE: ! 402: buffer.code = TYPE_CODE_ENUM; ! 403: break; ! 404: ! 405: default: ! 406: abort (); ! 407: } ! 408: ! 409: fwrite (&buffer, sizeof buffer, 1, symfile); ! 410: ! 411: switch (TREE_CODE (next)) ! 412: { ! 413: case ARRAY_TYPE: ! 414: if (buffer.nfields) ! 415: symout_array_domain (next); ! 416: break; ! 417: ! 418: case RECORD_TYPE: ! 419: case UNION_TYPE: ! 420: symout_record_fields (next); ! 421: break; ! 422: ! 423: case ENUMERAL_TYPE: ! 424: symout_enum_values (next); ! 425: break; ! 426: ! 427: case INTEGER_TYPE: ! 428: if (buffer.nfields) ! 429: symout_range_bounds (next); ! 430: } ! 431: } ! 432: ! 433: for (next = types, i = 0; ! 434: next; ! 435: next = TREE_CHAIN (next), i++) ! 436: { ! 437: switch (TREE_CODE (next)) ! 438: { ! 439: case RECORD_TYPE: ! 440: case UNION_TYPE: ! 441: symout_record_field_names (next); ! 442: break; ! 443: ! 444: case ENUMERAL_TYPE: ! 445: symout_enum_value_names (next); ! 446: break; ! 447: } ! 448: } ! 449: } ! 450: ! 451: /* Return nonzero if TYPE's range of possible values ! 452: is not the full range allowed by the number of bits it has. ! 453: TYPE is assumed to be an INTEGER_TYPE or ENUMERAL_TYPE. */ ! 454: ! 455: static int ! 456: subrange_p (type) ! 457: tree type; ! 458: { ! 459: int uns = TREE_UNSIGNED (type); ! 460: ! 461: if (TYPE_PRECISION (type) >= HOST_BITS_PER_INT) ! 462: { ! 463: if (uns) ! 464: return integer_zerop (TYPE_MIN_VALUE (type)) ! 465: && TREE_INT_CST_LOW (TYPE_MAX_VALUE (type)) == 0 ! 466: && (TREE_INT_CST_HIGH (TYPE_MAX_VALUE (type)) ! 467: == (1 << (TYPE_PRECISION (type) - HOST_BITS_PER_INT)) - 1); ! 468: return TREE_INT_CST_LOW (TYPE_MIN_VALUE (type)) == 0 ! 469: && TREE_INT_CST_LOW (TYPE_MAX_VALUE (type)) == 0 ! 470: && (TREE_INT_CST_HIGH (TYPE_MIN_VALUE (type)) ! 471: == (-1) << (TYPE_PRECISION (type) - 1 - HOST_BITS_PER_INT)) ! 472: && (TREE_INT_CST_HIGH (TYPE_MAX_VALUE (type)) ! 473: == (1 << (TYPE_PRECISION (type) - 1 - HOST_BITS_PER_INT)) - 1); ! 474: } ! 475: ! 476: if (uns) ! 477: return integer_zerop (TYPE_MIN_VALUE (type)) ! 478: && (TREE_INT_CST_LOW (TYPE_MAX_VALUE (type)) ! 479: == (1 << TYPE_PRECISION (type)) - 1); ! 480: else ! 481: return (TREE_INT_CST_LOW (TYPE_MIN_VALUE (type)) ! 482: == (-1) << (TYPE_PRECISION (type) - 1)) ! 483: && (TREE_INT_CST_LOW (TYPE_MAX_VALUE (type)) ! 484: == (1 << (TYPE_PRECISION (type) - 1)) - 1); ! 485: } ! 486: ! 487: /* Functions to output the "fields" of various kinds of types. ! 488: These assume that next_address has already been incremented to ! 489: cover these fields, and the fields of all the other types being ! 490: output in this batch; so next_address can be used to allocate ! 491: space to store field names, etc. */ ! 492: ! 493: static void ! 494: symout_array_domain (type) ! 495: tree type; ! 496: { ! 497: struct field buffer; ! 498: ! 499: buffer.bitpos = 0; ! 500: buffer.bitsize = 0; ! 501: buffer.type = (struct type *) TYPE_OUTPUT_ADDRESS (TYPE_DOMAIN (type)); ! 502: buffer.name = 0; ! 503: fwrite (&buffer, sizeof (struct field), 1, symfile); ! 504: } ! 505: ! 506: static void ! 507: symout_range_bounds (type) ! 508: tree type; ! 509: { ! 510: struct field buffer; ! 511: ! 512: buffer.bitpos = TREE_INT_CST_LOW (TYPE_MIN_VALUE (type)); ! 513: buffer.bitsize = 0; ! 514: buffer.type = (struct type *) TYPE_OUTPUT_ADDRESS (type); ! 515: buffer.name = 0; ! 516: fwrite (&buffer, sizeof (struct field), 1, symfile); ! 517: ! 518: buffer.bitpos = TREE_INT_CST_LOW (TYPE_MAX_VALUE (type)); ! 519: buffer.bitsize = 0; ! 520: buffer.type = (struct type *) TYPE_OUTPUT_ADDRESS (type); ! 521: buffer.name = 0; ! 522: fwrite (&buffer, sizeof (struct field), 1, symfile); ! 523: } ! 524: ! 525: static void ! 526: symout_record_fields (type) ! 527: tree type; ! 528: { ! 529: struct field buffer; ! 530: register tree field; ! 531: ! 532: for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) ! 533: { ! 534: buffer.bitpos = DECL_OFFSET (field); ! 535: buffer.bitsize ! 536: = (TREE_PACKED (field) ! 537: ? TREE_INT_CST_LOW (DECL_SIZE (field)) * DECL_SIZE_UNIT (field) ! 538: : 0); ! 539: buffer.type = (struct type *) TYPE_OUTPUT_ADDRESS (TREE_TYPE (field)); ! 540: if (DECL_NAME (field)) ! 541: { ! 542: buffer.name = (char *) next_address; ! 543: symout_strings_skip (0, IDENTIFIER_LENGTH (DECL_NAME (field)), 0, 0); ! 544: } ! 545: else ! 546: buffer.name = 0; ! 547: fwrite (&buffer, sizeof (struct field), 1, symfile); ! 548: } ! 549: } ! 550: ! 551: static void ! 552: symout_enum_values (type) ! 553: tree type; ! 554: { ! 555: struct field buffer; ! 556: register tree link, value; ! 557: ! 558: for (link = TYPE_VALUES (type); link; link = TREE_CHAIN (link)) ! 559: { ! 560: value = TREE_VALUE (link); ! 561: buffer.bitpos = TREE_INT_CST_LOW (value); ! 562: buffer.bitsize = 0; ! 563: buffer.type = (struct type *) TYPE_OUTPUT_ADDRESS (type); ! 564: buffer.name = (char *) next_address; ! 565: symout_strings_skip (0, IDENTIFIER_LENGTH (TREE_PURPOSE (link)), 0, 0); ! 566: fwrite (&buffer, sizeof buffer, 1, symfile); ! 567: } ! 568: } ! 569: ! 570: /* Output field names or value names for the fields of a type. ! 571: This is called, for the types that need it, after the fields ! 572: have been output for all the types in the batch. ! 573: We do not update next_address here, because it has already been ! 574: updated for all the names in all the fields in all the types. */ ! 575: ! 576: static void ! 577: symout_record_field_names (type) ! 578: tree type; ! 579: { ! 580: register tree field; ! 581: ! 582: for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) ! 583: if (DECL_NAME (field)) ! 584: symout_strings_print (IDENTIFIER_POINTER (DECL_NAME (field)), ! 585: IDENTIFIER_LENGTH (DECL_NAME (field)), ! 586: 0, 0); ! 587: } ! 588: ! 589: static void ! 590: symout_enum_value_names (type) ! 591: tree type; ! 592: { ! 593: register tree value; ! 594: ! 595: for (value = TYPE_VALUES (type); value; value = TREE_CHAIN (value)) ! 596: symout_strings_print (IDENTIFIER_POINTER (TREE_PURPOSE (value)), ! 597: IDENTIFIER_LENGTH (TREE_PURPOSE (value)), ! 598: 0, 0); ! 599: } ! 600: ! 601: /* Output the symbols of a block, given the list of decl nodes. ! 602: Store the file addresses at which the symbols are output ! 603: into ADDR_BUFFER, a vector which has just the right length. ! 604: ! 605: If FILTER is 1, do only the private symbols in DECLS. ! 606: If FILTER is 2, do only the public ones (but no externals). ! 607: If FILTER is 0, do all (except external functions). */ ! 608: ! 609: static void ! 610: symout_block_symbols (decls, addr_buffer, filter) ! 611: tree decls; ! 612: int *addr_buffer; ! 613: int filter; ! 614: { ! 615: register tree decl; ! 616: struct symbol buffer; ! 617: register int i; ! 618: ! 619: for (decl = decls, i = 0; decl; decl = TREE_CHAIN (decl)) ! 620: { ! 621: register name_address = next_address; ! 622: ! 623: if (filter == (TREE_PUBLIC (decl) ? 1 : 2)) ! 624: continue; ! 625: ! 626: /* Do not mention external functions. ! 627: Let their own files mention them. ! 628: In the top blocks, don't mention external anything. */ ! 629: ! 630: if (TREE_EXTERNAL (decl) ! 631: && (filter || TREE_CODE (TREE_TYPE (decl)) == FUNCTION_TYPE)) ! 632: continue; ! 633: ! 634: if (TREE_TYPE (decl) == error_mark_node) ! 635: continue; ! 636: ! 637: symout_strings (IDENTIFIER_POINTER (DECL_NAME (decl)), ! 638: IDENTIFIER_LENGTH (DECL_NAME (decl)), ! 639: 0, 0); ! 640: addr_buffer[i] = next_address; ! 641: buffer.name = (char *) name_address; ! 642: buffer.namespace = VAR_NAMESPACE; ! 643: buffer.type = (struct type *) TYPE_OUTPUT_ADDRESS (TREE_TYPE (decl)); ! 644: switch (TREE_CODE (decl)) ! 645: { ! 646: case PARM_DECL: ! 647: buffer.class = LOC_ARG; ! 648: buffer.value.value = DECL_OFFSET (decl) / BITS_PER_UNIT; ! 649: break; ! 650: ! 651: case VAR_DECL: ! 652: case RESULT_DECL: ! 653: if (TREE_STATIC (decl) || TREE_EXTERNAL (decl)) ! 654: { ! 655: if (! TREE_PUBLIC (decl) || DECL_INITIAL (decl)) ! 656: { ! 657: char *str = XSTR (XEXP (DECL_RTL (decl), 0), 0); ! 658: fprintf (asmfile, "\t.gdbsym "); ! 659: ASM_OUTPUT_LABELREF (asmfile, str); ! 660: fprintf (asmfile, ",%d\n", ! 661: next_address + (char *)&buffer.value - (char *)&buffer); ! 662: buffer.class = LOC_STATIC; ! 663: } ! 664: else ! 665: /* Uninitialized public symbols are output as .comm; ! 666: Tell GDB to get address from loader global symbol. ! 667: Also come here for symbols declared extern. */ ! 668: buffer.class = LOC_EXTERNAL; ! 669: } ! 670: else ! 671: { ! 672: if (GET_CODE (DECL_RTL (decl)) == REG) ! 673: { ! 674: buffer.class = LOC_REGISTER; ! 675: buffer.value.value = REGNO (DECL_RTL (decl)); ! 676: /* Detect vars that were optimized entirely away. */ ! 677: if (buffer.value.value == -1) ! 678: buffer.class = LOC_CONST; ! 679: } ! 680: /* Locals in memory are expected to be addressed as ! 681: (PLUS (REG ...) (CONST_INT ...)). ! 682: Bomb out if that is not so. */ ! 683: else if (GET_CODE (DECL_RTL (decl)) == MEM) ! 684: { ! 685: register rtx addr = XEXP (DECL_RTL (decl), 0); ! 686: if (GET_CODE (addr) != PLUS && GET_CODE (addr) != MINUS) ! 687: abort (); ! 688: if (GET_CODE (XEXP (addr, 1)) != CONST_INT) ! 689: abort (); ! 690: buffer.class = LOC_LOCAL; ! 691: buffer.value.value = INTVAL (XEXP (addr, 1)); ! 692: if (GET_CODE (addr) == MINUS) ! 693: buffer.value.value = - buffer.value.value; ! 694: } ! 695: else ! 696: abort (); ! 697: } ! 698: break; ! 699: ! 700: case TYPE_DECL: ! 701: buffer.class = LOC_TYPEDEF; ! 702: buffer.value.value = 0; ! 703: break; ! 704: ! 705: case CONST_DECL: ! 706: buffer.class = LOC_CONST; ! 707: buffer.value.value = TREE_INT_CST_LOW (DECL_INITIAL (decl)); ! 708: break; ! 709: ! 710: case FUNCTION_DECL: ! 711: if (DECL_INITIAL (decl)) ! 712: { ! 713: buffer.class = LOC_BLOCK; ! 714: buffer.value.value = DECL_BLOCK_SYMTAB_ADDRESS (decl); ! 715: } ! 716: else ! 717: buffer.class = LOC_EXTERNAL; ! 718: } ! 719: ! 720: fwrite (&buffer, sizeof buffer, 1, symfile); ! 721: next_address += sizeof buffer; ! 722: i++; ! 723: } ! 724: } ! 725: ! 726: /* Output the tags (struct, union and enum definitions) for a block, ! 727: given a list of them (a chain of TREE_LIST nodes) in TAGS. ! 728: Store their addresses in the file into ADDR_BUFFER. */ ! 729: ! 730: static void ! 731: symout_block_tags (tags, addr_buffer) ! 732: tree tags; ! 733: int *addr_buffer; ! 734: { ! 735: register tree tag; ! 736: struct symbol buffer; ! 737: register int i; ! 738: ! 739: for (tag = tags, i = 0; tag; tag = TREE_CHAIN (tag), i++) ! 740: { ! 741: buffer.name = (char *) next_address; ! 742: ! 743: symout_strings (IDENTIFIER_POINTER (TREE_PURPOSE (tag)), ! 744: IDENTIFIER_LENGTH (TREE_PURPOSE (tag)), ! 745: 0, 0); ! 746: addr_buffer[i] = next_address; ! 747: buffer.namespace = STRUCT_NAMESPACE; ! 748: buffer.type = (struct type *) TYPE_OUTPUT_ADDRESS (TREE_VALUE (tag)); ! 749: buffer.class = LOC_TYPEDEF; ! 750: buffer.value.value = 0; ! 751: ! 752: fwrite (&buffer, sizeof buffer, 1, symfile); ! 753: next_address += sizeof buffer; ! 754: } ! 755: } ! 756: ! 757: /* Output all the data structure for a "block" ! 758: (any binding contour). ! 759: DECLS is the chain of declarations of variables in this block. ! 760: TAGS is the list of struct, union and enum tag definitions of this block. ! 761: SUPERBLOCK_ADDRESS is the symtab file address of the containing block's ! 762: data structure. */ ! 763: ! 764: int ! 765: symout_block (decls, tags, args, superblock_address) ! 766: tree decls; ! 767: tree tags; ! 768: tree args; ! 769: int superblock_address; ! 770: { ! 771: register tree decl; ! 772: register int i; ! 773: register int *addr_buffer; ! 774: struct block buffer; ! 775: int n_decls, n_tags, n_args, total; ! 776: register struct blockvec_elt *velt; ! 777: int block_address; ! 778: ! 779: for (decl = decls, i = 0; decl; decl = TREE_CHAIN (decl)) ! 780: if (! TREE_EXTERNAL (decl) ! 781: || TREE_CODE (TREE_TYPE (decl)) != FUNCTION_TYPE) ! 782: i++; ! 783: ! 784: n_decls = i; ! 785: ! 786: for (decl = args, i = 0; decl; decl = TREE_CHAIN (decl), i++); ! 787: n_args = i; ! 788: ! 789: for (decl = tags, i = 0; decl; decl = TREE_CHAIN (decl), i++); ! 790: n_tags = i; ! 791: ! 792: total = n_decls + n_args + n_tags; ! 793: ! 794: addr_buffer = (int *) alloca (total * sizeof (int)); ! 795: ! 796: symout_block_symbols (args, addr_buffer, 0); ! 797: symout_block_symbols (decls, addr_buffer + n_args, 0); ! 798: symout_block_tags (tags, addr_buffer + n_decls + n_args); ! 799: ! 800: velt = (struct blockvec_elt *) xmalloc (sizeof (struct blockvec_elt)); ! 801: velt->next = blockvec; ! 802: velt->address = next_address; ! 803: blockvec = velt; ! 804: ! 805: buffer.startaddr = 0; ! 806: buffer.endaddr = 0; ! 807: buffer.superblock = (struct block *) superblock_address; ! 808: buffer.function = 0; ! 809: buffer.nsyms = total; ! 810: ! 811: block_address = next_address; ! 812: fwrite (&buffer, sizeof buffer - sizeof buffer.sym, 1, symfile); ! 813: next_address += sizeof buffer - sizeof buffer.sym; ! 814: ! 815: fwrite (addr_buffer, sizeof (int), total, symfile); ! 816: next_address += total * sizeof (int); ! 817: ! 818: fprintf (asmfile, "\t.gdbblock %d,%d\n", total_blocks + 2, block_address); ! 819: total_blocks++; ! 820: ! 821: return block_address; ! 822: } ! 823: ! 824: /* Walk STMT, the body of a function, and output symtab data on ! 825: all the blocks that compose it and all symbols inside them. ! 826: ARGS is a chain of decls for argument variables of the function. ! 827: SUPERBLOCK_ADDRESS is the address of symbol data for the ! 828: innermost block containing STMT; it is used for recursive calls, ! 829: and is always 0 for the outermost call (since the containing ! 830: block for a function is output later than the function). */ ! 831: ! 832: int ! 833: symout_function (stmt, args, superblock_address) ! 834: register tree stmt; ! 835: tree args; ! 836: int superblock_address; ! 837: { ! 838: int address = superblock_address; ! 839: ! 840: while (stmt) ! 841: { ! 842: switch (TREE_CODE (stmt)) ! 843: { ! 844: case COMPOUND_STMT: ! 845: case LOOP_STMT: ! 846: symout_function (STMT_BODY (stmt), 0, address); ! 847: break; ! 848: ! 849: case IF_STMT: ! 850: symout_function (STMT_THEN (stmt), 0, address); ! 851: symout_function (STMT_ELSE (stmt), 0, address); ! 852: break; ! 853: ! 854: case LET_STMT: ! 855: address = ! 856: symout_block (STMT_VARS (stmt), STMT_TYPE_TAGS (stmt), args, ! 857: superblock_address); ! 858: ! 859: symout_function (STMT_BODY (stmt), 0, address); ! 860: } ! 861: stmt = TREE_CHAIN (stmt); ! 862: } ! 863: return address; ! 864: } ! 865: ! 866: /* Output all the data structure for a top two blocks in a compilation. ! 867: The top block is for public (global) symbols; ! 868: the next one is for private (this file only) symbols. ! 869: ! 870: DECLS is the chain of declarations of variables in this block. ! 871: TAGS is the list of struct, union and enum tag definitions. */ ! 872: ! 873: void ! 874: symout_top_blocks (decls, tags) ! 875: tree decls; ! 876: tree tags; ! 877: { ! 878: register tree decl; ! 879: register int i; ! 880: register int *addr_buffer; ! 881: struct block buffer; ! 882: int n_decls, n_tags; ! 883: register struct blockvec_elt *velt; ! 884: int top_block_addr; ! 885: ! 886: /* First do the public-symbols block. */ ! 887: ! 888: for (decl = decls, i = 0; decl; decl = TREE_CHAIN (decl)) ! 889: if (TREE_PUBLIC (decl) && ! TREE_EXTERNAL (decl)) ! 890: i++; ! 891: n_decls = i; ! 892: ! 893: addr_buffer = (int *) alloca (n_decls * sizeof (int)); ! 894: ! 895: symout_block_symbols (decls, addr_buffer, 2); ! 896: ! 897: fprintf (asmfile, ".text 0\n\t.gdbend 0\n"); ! 898: fprintf (asmfile, "\t.gdbblock 0,%d\n", next_address); ! 899: ! 900: total_blocks++; ! 901: velt = (struct blockvec_elt *) xmalloc (sizeof (struct blockvec_elt)); ! 902: velt->next = blockvec; ! 903: velt->address = next_address; ! 904: blockvec = velt; ! 905: ! 906: top_block_addr = next_address; ! 907: ! 908: buffer.startaddr = 0; ! 909: buffer.endaddr = 0; ! 910: buffer.superblock = 0; ! 911: buffer.function = 0; ! 912: buffer.nsyms = n_decls;; ! 913: ! 914: fwrite (&buffer, sizeof buffer - sizeof buffer.sym, 1, symfile); ! 915: next_address += sizeof buffer - sizeof buffer.sym; ! 916: ! 917: fwrite (addr_buffer, sizeof (int), n_decls, symfile); ! 918: next_address += n_decls * sizeof (int); ! 919: ! 920: /* Next do the private-symbols block. */ ! 921: ! 922: for (decl = decls, i = 0; decl; decl = TREE_CHAIN (decl)) ! 923: if (! TREE_PUBLIC (decl) && ! TREE_EXTERNAL (decl)) ! 924: i++; ! 925: n_decls = i; ! 926: ! 927: for (decl = tags, i = 0; decl; decl = TREE_CHAIN (decl), i++); ! 928: n_tags = i; ! 929: ! 930: addr_buffer = (int *) alloca ((n_decls + n_tags) * sizeof (int)); ! 931: ! 932: symout_block_symbols (decls, addr_buffer, 1); ! 933: symout_block_tags (tags, addr_buffer + n_decls); ! 934: ! 935: fprintf (asmfile, "\t.gdbend 1\n"); ! 936: fprintf (asmfile, "\t.gdbblock 1,%d\n", next_address); ! 937: ! 938: total_blocks++; ! 939: velt = (struct blockvec_elt *) xmalloc (sizeof (struct blockvec_elt)); ! 940: velt->next = blockvec; ! 941: velt->address = next_address; ! 942: blockvec = velt; ! 943: ! 944: buffer.startaddr = 0; ! 945: buffer.endaddr = 0; ! 946: buffer.superblock = (struct block *) top_block_addr; ! 947: buffer.function = 0; ! 948: buffer.nsyms = n_decls + n_tags;; ! 949: ! 950: fwrite (&buffer, sizeof buffer - sizeof buffer.sym, 1, symfile); ! 951: next_address += sizeof buffer - sizeof buffer.sym; ! 952: ! 953: fwrite (addr_buffer, sizeof (int), n_decls + n_tags, symfile); ! 954: next_address += (n_decls + n_tags) * sizeof (int); ! 955: } ! 956: ! 957: /* Output the source-line-number information. */ ! 958: ! 959: /* Output a `struct source' for the source file described by F. ! 960: Return the address-in-the-symseg of the `struct source'. */ ! 961: ! 962: static int ! 963: symout_source_file (f) ! 964: struct gdbfile *f; ! 965: { ! 966: /* Make the `struct source' big enough for as many lines as ! 967: this file has. */ ! 968: int size = sizeof (struct source) + (f->nlines - 1) * sizeof (struct line); ! 969: struct source *buffer ! 970: = (struct source *) alloca (size); ! 971: int addr; ! 972: ! 973: /* Use zero for the line data, since assembler will store the real data. */ ! 974: bzero (buffer, size); ! 975: ! 976: /* Output the file's name as a string. The assembler doesn't know this. */ ! 977: buffer->name = (char *) next_address; ! 978: symout_strings (f->name, 0, 0, 0); ! 979: buffer->nlines = f->nlines; ! 980: ! 981: /* Write the structure. */ ! 982: addr = next_address; ! 983: fwrite (buffer, 1, size, symfile); ! 984: next_address += size; ! 985: ! 986: /* Tell assembler where to write the real line-number data. */ ! 987: fprintf (asmfile, "\t.gdblinetab %d,%d\n", ! 988: f->filenum, addr + sizeof (int)); ! 989: ! 990: return addr; ! 991: } ! 992: ! 993: /* Output the `struct sourcevector' which describes all the ! 994: source files and points a `struct source' for each one. */ ! 995: ! 996: static int ! 997: symout_sources () ! 998: { ! 999: register struct gdbfile *f; ! 1000: int nfiles = 0; ! 1001: struct sourcevector *s; ! 1002: int i; ! 1003: int size; ! 1004: int addr; ! 1005: ! 1006: /* Count number of files to determine size of the sourcevector. */ ! 1007: for (f = gdbfiles; f; f = f->next) ! 1008: ++nfiles; ! 1009: ! 1010: /* Allocate buffer for the sourcevector and record its length. */ ! 1011: size = sizeof (int) + nfiles * sizeof (struct source *); ! 1012: s = (struct sourcevector *) alloca (size); ! 1013: s->length = nfiles; ! 1014: ! 1015: /* Output a `struct source' for each file; put address into sourcevector. */ ! 1016: for (f = gdbfiles, i = 0; f; f = f->next, i++) ! 1017: s->source[i] = (struct source *) symout_source_file (f); ! 1018: ! 1019: /* Output the sourcevector. */ ! 1020: addr = next_address; ! 1021: fwrite (s, 1, size, symfile); ! 1022: next_address += size; ! 1023: return addr; ! 1024: } ! 1025: ! 1026: /* Call here at the end of compilation, after outputting all the ! 1027: blocks and symbols, to output the blockvector and typevector ! 1028: and close the symbol table file. FILETIME is source file's ! 1029: creation time. */ ! 1030: ! 1031: void ! 1032: symout_finish (filename, filetime) ! 1033: char *filename; ! 1034: int filetime; ! 1035: { ! 1036: int *blockvector = (int *) alloca ((total_blocks + 1) * sizeof (int)); ! 1037: int *typevector = (int *) alloca ((total_types + 1) * sizeof (int)); ! 1038: int now = time (0); ! 1039: register int i; ! 1040: struct symbol_root buffer; ! 1041: char dir[MAXNAMLEN]; ! 1042: ! 1043: buffer.language = language_c; ! 1044: buffer.blockvector = (struct blockvector *) next_address; ! 1045: ! 1046: /* The two blocks at the beginning of the chain ! 1047: are the file's private symbols block and public symbols block. ! 1048: They belong at the front of the blockvector, in that order. */ ! 1049: blockvector[2] = blockvec->address; ! 1050: blockvec = blockvec->next; ! 1051: blockvector[1] = blockvec->address; ! 1052: blockvec = blockvec->next; ! 1053: ! 1054: /* The rest of the blocks are in the chain in reverse order. */ ! 1055: for (i = total_blocks; i > 2; i--) ! 1056: { ! 1057: blockvector[i] = blockvec->address; ! 1058: blockvec = blockvec->next; ! 1059: } ! 1060: blockvector[0] = total_blocks; ! 1061: ! 1062: fwrite (blockvector, sizeof (int), total_blocks + 1, symfile); ! 1063: next_address += sizeof (int) * (total_blocks + 1); ! 1064: ! 1065: buffer.typevector = (struct typevector *) next_address; ! 1066: ! 1067: for (i = total_types; i > 0; i--) ! 1068: { ! 1069: typevector[i] = typevec->address; ! 1070: typevec = typevec->next; ! 1071: } ! 1072: typevector[0] = total_types; ! 1073: ! 1074: fwrite (typevector, sizeof (int), total_types + 1, symfile); ! 1075: next_address += sizeof (int) * (total_types + 1); ! 1076: ! 1077: buffer.sourcevector = (struct sourcevector *) symout_sources (); ! 1078: ! 1079: buffer.format = 1; ! 1080: buffer.textrel = 0; /* These four will be set up by linker. */ ! 1081: buffer.datarel = 0; /* Make them 0 now, which is right for */ ! 1082: buffer.bssrel = 0; /* looking at the .o file in gdb. */ ! 1083: buffer.ldsymoff = 0; ! 1084: ! 1085: buffer.version = (char *) next_address; ! 1086: symout_strings (ctime (&filetime), 0, 0, 0); ! 1087: ! 1088: buffer.compilation = (char *) next_address; ! 1089: symout_strings (ctime (&now), 0, 0, 0); ! 1090: ! 1091: buffer.filename = (char *) next_address; ! 1092: symout_strings (filename, 0, 0, 0); ! 1093: ! 1094: buffer.filedir = (char *) next_address; ! 1095: #ifdef USG ! 1096: strcpy (dir, getcwd (dir, MAXNAMLEN)); ! 1097: #else ! 1098: #ifndef VMS ! 1099: getwd (dir); ! 1100: #else ! 1101: abort (); ! 1102: #endif ! 1103: #endif ! 1104: symout_strings (dir, 0, 0, 0); ! 1105: ! 1106: fflush (symfile); ! 1107: ! 1108: if (ferror (symfile) != 0) ! 1109: fatal_io_error (symfile_name); ! 1110: ! 1111: buffer.length = next_address; ! 1112: ! 1113: if (lseek (fileno (symfile), 0, 0) < 0) ! 1114: pfatal_with_name (symfile_name); ! 1115: if (write (fileno (symfile), &buffer, sizeof buffer) < 0) ! 1116: pfatal_with_name (symfile_name); ! 1117: close (fileno (symfile)); ! 1118: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.