📄 dwarfread.c
字号:
DESCRIPTION Translate the DWARF line number information to gdb form. The ".line" section contains one or more line number tables, one for each ".line" section from the objects that were linked. The AT_stmt_list attribute for each TAG_source_file entry in the ".debug" section contains the offset into the ".line" section for the start of the table for that file. The table itself has the following structure: <table length><base address><source statement entry> 4 bytes 4 bytes 10 bytes The table length is the total size of the table, including the 4 bytes for the length information. The base address is the address of the first instruction generated for the source file. Each source statement entry has the following structure: <line number><statement position><address delta> 4 bytes 2 bytes 4 bytes The line number is relative to the start of the file, starting with line 1. The statement position either -1 (0xFFFF) or the number of characters from the beginning of the line to the beginning of the statement. The address delta is the difference between the base address and the address of the first instruction for the statement. Note that we must copy the bytes from the packed table to our local variables before attempting to use them, to avoid alignment problems on some machines, particularly RISC processors.BUGS Does gdb expect the line numbers to be sorted? They are now by chance/luck, but are not required to be. (FIXME) The line with number 0 is unused, gdb apparently can discover the span of the last line some other way. How? (FIXME) */static voiddecode_line_numbers (linetable) char *linetable;{ char *tblscan; char *tblend; unsigned long length; unsigned long base; unsigned long line; unsigned long pc; if (linetable != NULL) { tblscan = tblend = linetable; length = target_to_host (tblscan, SIZEOF_LINETBL_LENGTH, GET_UNSIGNED, current_objfile); tblscan += SIZEOF_LINETBL_LENGTH; tblend += length; base = target_to_host (tblscan, TARGET_FT_POINTER_SIZE (objfile), GET_UNSIGNED, current_objfile); tblscan += TARGET_FT_POINTER_SIZE (objfile); base += baseaddr; while (tblscan < tblend) { line = target_to_host (tblscan, SIZEOF_LINETBL_LINENO, GET_UNSIGNED, current_objfile); tblscan += SIZEOF_LINETBL_LINENO + SIZEOF_LINETBL_STMT; pc = target_to_host (tblscan, SIZEOF_LINETBL_DELTA, GET_UNSIGNED, current_objfile); tblscan += SIZEOF_LINETBL_DELTA; pc += base; if (line != 0) { record_line (current_subfile, line, pc); } } }}/*LOCAL FUNCTION locval -- compute the value of a location attributeSYNOPSIS static int locval (char *loc)DESCRIPTION Given pointer to a string of bytes that define a location, compute the location and return the value. When computing values involving the current value of the frame pointer, the value zero is used, which results in a value relative to the frame pointer, rather than the absolute value. This is what GDB wants anyway. When the result is a register number, the global isreg flag is set, otherwise it is cleared. This is a kludge until we figure out a better way to handle the problem. Gdb's design does not mesh well with the DWARF notion of a location computing interpreter, which is a shame because the flexibility goes unused.NOTES Note that stack[0] is unused except as a default error return. Note that stack overflow is not yet handled. */static intlocval (loc) char *loc;{ unsigned short nbytes; unsigned short locsize; auto long stack[64]; int stacki; char *end; long regno; int loc_atom_code; int loc_value_size; nbytes = attribute_size (AT_location); locsize = target_to_host (loc, nbytes, GET_UNSIGNED, current_objfile); loc += nbytes; end = loc + locsize; stacki = 0; stack[stacki] = 0; isreg = 0; offreg = 0; loc_value_size = TARGET_FT_LONG_SIZE (current_objfile); while (loc < end) { loc_atom_code = target_to_host (loc, SIZEOF_LOC_ATOM_CODE, GET_UNSIGNED, current_objfile); loc += SIZEOF_LOC_ATOM_CODE; switch (loc_atom_code) { case 0: /* error */ loc = end; break; case OP_REG: /* push register (number) */ stack[++stacki] = target_to_host (loc, loc_value_size, GET_UNSIGNED, current_objfile); loc += loc_value_size; isreg = 1; break; case OP_BASEREG: /* push value of register (number) */ /* Actually, we compute the value as if register has 0 */ offreg = 1; regno = target_to_host (loc, loc_value_size, GET_UNSIGNED, current_objfile); loc += loc_value_size; if (regno == R_FP) { stack[++stacki] = 0; } else { stack[++stacki] = 0; SQUAWK (("BASEREG %d not handled!", regno)); } break; case OP_ADDR: /* push address (relocated address) */ stack[++stacki] = target_to_host (loc, loc_value_size, GET_UNSIGNED, current_objfile); loc += loc_value_size; break; case OP_CONST: /* push constant (number) FIXME: signed or unsigned! */ stack[++stacki] = target_to_host (loc, loc_value_size, GET_SIGNED, current_objfile); loc += loc_value_size; break; case OP_DEREF2: /* pop, deref and push 2 bytes (as a long) */ SQUAWK (("OP_DEREF2 address 0x%x not handled", stack[stacki])); break; case OP_DEREF4: /* pop, deref and push 4 bytes (as a long) */ SQUAWK (("OP_DEREF4 address 0x%x not handled", stack[stacki])); break; case OP_ADD: /* pop top 2 items, add, push result */ stack[stacki - 1] += stack[stacki]; stacki--; break; } } return (stack[stacki]);}/*LOCAL FUNCTION read_ofile_symtab -- build a full symtab entry from chunk of DIE'sSYNOPSIS static struct symtab *read_ofile_symtab (struct partial_symtab *pst)DESCRIPTION When expanding a partial symbol table entry to a full symbol table entry, this is the function that gets called to read in the symbols for the compilation unit. Returns a pointer to the newly constructed symtab (which is now the new first one on the objfile's symtab list). */static struct symtab *read_ofile_symtab (pst) struct partial_symtab *pst;{ struct cleanup *back_to; unsigned long lnsize; file_ptr foffset; bfd *abfd; char lnsizedata[SIZEOF_LINETBL_LENGTH]; abfd = pst -> objfile -> obfd; current_objfile = pst -> objfile; /* Allocate a buffer for the entire chunk of DIE's for this compilation unit, seek to the location in the file, and read in all the DIE's. */ diecount = 0; dbsize = DBLENGTH (pst); dbbase = xmalloc (dbsize); dbroff = DBROFF(pst); foffset = DBFOFF(pst) + dbroff; base_section_offsets = pst->section_offsets; baseaddr = ANOFFSET (pst->section_offsets, 0); if (bfd_seek (abfd, foffset, L_SET) || (bfd_read (dbbase, dbsize, 1, abfd) != dbsize)) { free (dbbase); error ("can't read DWARF data"); } back_to = make_cleanup (free, dbbase); /* If there is a line number table associated with this compilation unit then read the size of this fragment in bytes, from the fragment itself. Allocate a buffer for the fragment and read it in for future processing. */ lnbase = NULL; if (LNFOFF (pst)) { if (bfd_seek (abfd, LNFOFF (pst), L_SET) || (bfd_read ((PTR) lnsizedata, sizeof (lnsizedata), 1, abfd) != sizeof (lnsizedata))) { error ("can't read DWARF line number table size"); } lnsize = target_to_host (lnsizedata, SIZEOF_LINETBL_LENGTH, GET_UNSIGNED, pst -> objfile); lnbase = xmalloc (lnsize); if (bfd_seek (abfd, LNFOFF (pst), L_SET) || (bfd_read (lnbase, lnsize, 1, abfd) != lnsize)) { free (lnbase); error ("can't read DWARF line numbers"); } make_cleanup (free, lnbase); } process_dies (dbbase, dbbase + dbsize, pst -> objfile); do_cleanups (back_to); current_objfile = NULL; return (pst -> objfile -> symtabs);}/*LOCAL FUNCTION psymtab_to_symtab_1 -- do grunt work for building a full symtab entrySYNOPSIS static void psymtab_to_symtab_1 (struct partial_symtab *pst)DESCRIPTION Called once for each partial symbol table entry that needs to be expanded into a full symbol table entry.*/static voidpsymtab_to_symtab_1 (pst) struct partial_symtab *pst;{ int i; struct cleanup *old_chain; if (pst != NULL) { if (pst->readin) { warning ("psymtab for %s already read in. Shouldn't happen.", pst -> filename); } else { /* Read in all partial symtabs on which this one is dependent */ for (i = 0; i < pst -> number_of_dependencies; i++) { if (!pst -> dependencies[i] -> readin) { /* Inform about additional files that need to be read in. */ if (info_verbose) { fputs_filtered (" ", stdout); wrap_here (""); fputs_filtered ("and ", stdout); wrap_here (""); printf_filtered ("%s...", pst -> dependencies[i] -> filename); wrap_here (""); fflush (stdout); /* Flush output */ } psymtab_to_symtab_1 (pst -> dependencies[i]); } } if (DBLENGTH (pst)) /* Otherwise it's a dummy */ { buildsym_init (); old_chain = make_cleanup (really_free_pendings, 0); pst -> symtab = read_ofile_symtab (pst); if (info_verbose) { printf_filtered ("%d DIE's, sorting...", diecount); wrap_here (""); fflush (stdout); } sort_symtab_syms (pst -> symtab); do_cleanups (old_chain); } pst -> readin = 1; } }}/*LOCAL FUNCTION dwarf_psymtab_to_symtab -- build a full symtab entry from partial oneSYNOPSIS static void dwarf_psymtab_to_symtab (struct partial_symtab *pst)DESCRIPTION This is the DWARF support entry point for building a full symbol table entry from a partial symbol table entry. We are passed a pointer to the partial symbol table entry that needs to be expanded.*/static voiddwarf_psymtab_to_symtab (pst) struct partial_symtab *pst;{ if (pst != NULL) { if (pst -> readin) { warning ("psymtab for %s already read in. Shouldn't happen.", pst -> filename); } else { if (DBLENGTH (pst) || pst -> number_of_dependencies) { /* Print the message now, before starting serious work, to avoid disconcerting pauses. */ if (info_verbose) { printf_filtered ("Reading in symbols for %s...", pst -> filename); fflush (stdout); } psymtab_to_symtab_1 (pst); #if 0 /* FIXME: Check to see what dbxread is doing here and see if we need to do an equivalent or is this something peculiar to stabs/a.out format. Match with global symbols. This only needs to be done once, after all of the symtabs and dependencies have been read in. */ scan_file_globals (pst -> objfile);#endif /* Finish up the verbose info message. */ if (info_verbose) { printf_filtered ("done.\n"); fflush (stdout); } } } }}/*LOCAL FUNCTION init_psymbol_list -- initialize storage for partial symbolsSYNOPSIS static void init_psymbol_list (struct objfile *objfile, int total_symbols)DESCRIPTION Initializes storage for all of the partial symbols that will be created by dwarf_build_psymtabs and subsidiaries. */static voidinit_psymbol_list (objfile, total_symbols) struct objfile *objfile; int total_symbols;{ /* Free any previously allocated psymbol lists. */ if (objfile -> global_psymbols.list) { mfree (objfile -> md, (PTR)objfile -> global_psymbols.list); } if (objfile -> static_psymbols.list) { mfree (objfile -> md, (PTR)objfile -> static_psymbols.list); } /* Current best guess is that there are approximately a twentieth of the total symbols (in a debugging file) are global or static oriented symbols */ objfile -> global_psymbols.size = total_symbols / 10; objfile -> static_psymbols.size = total_symbols / 10; objfile -> global_psymbols.next = objfile -> global_psymbols.list = (stru
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -