📄 dwarfread.c
字号:
/* DWARF debugging format support for GDB. Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc. Written by Fred Fish at Cygnus Support. Portions based on dbxread.c, mipsread.c, coffread.c, and dwarfread.c from a Data General SVR4 gdb port.This file is part of GDB.This program is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2 of the License, or(at your option) any later version.This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with this program; if not, write to the Free SoftwareFoundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *//* Important Note: This file is an adaptation of the original gdb dwarfread.c file which supported dwarf version 1. This file supports version 2 using an SGI supplied libdwarf library. Because of the interface change brought on by using the library, and because of changes in the format, this file is substantially changed from the original. It was written by someone with little knowledge of dwarf or gdb, so it is highly non-optimal and somewhat convoluted due to its history. In addition, all comments should be taken with a large grain of salt as they may be left over from the original and no longer apply. One open question is whether it would be better to make use of the types and globals sections to collect certain key information. Note: need to check for places where dwarf_dealloc should be called but isn't (for all child and sibling dies in particular). Note: we use sym->global is a flag for typecasts since they don't follow the normal conventions for our types, since they are constructed on the fly and don't have a proper dwarf entry to anchor them. */#include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#ifdef sgi#include <dem.h>#endif#include <unistd.h>#include <stdlib.h>#include <string.h>#include <sys/file.h>#include "file_formats.h"#include "symbols.h"#include "simutil.h"#include "symfile.h"#include "assoctab.h"#include "tcl_init.h"#include "sim_error.h" /* we're not depending on elf library, so provide some dummy defn */typedef void * Elf;#include "dwarf2.h"#include "libdwarf2.h"#define DIE_NAME(dip) (((dip)->at_name != NULL) ? (dip)->at_name : "")#define IS_CAST(sym) (sym->global != 0)int info_verbose; typedef Dwarf_Off DIE_REF; /* Reference to a DIE */typedef char BLOCK;struct dieinfo { Dwarf_Die ddie; /* pointer to dwarf library die data */ Dwarf_Die sibdie; /* pointer to dwarf library die data */ Dwarf_Die childdie; /* pointer to dwarf library die data */ DIE_REF die_ref; /* Offset of this DIE in debug sect */ Dwarf_Half die_tag; /* Tag for this DIE */ char * at_name; Dwarf_Off at_type;};typedef struct Execfile { ATHeader head; AssocTab *srcs; AssocTab *globals; AssocTab *gStructs; Dwarf_Debug dwarf;} Execfile;typedef struct Srcfile { ATHeader head; AssocTab *globals; VA lopc; VA hipc; DIE_REF dieref;} Srcfile;typedef struct Global { ATHeader head; DIE_REF dieref; Dwarf_Half dietag;} Global;static void scan_partial_symbols(Dwarf_Die, Execfile *exec, Srcfile *src );static void scan_compilation_units(Execfile *exec);static void basicdieinfo ( struct dieinfo *dip, Dwarf_Die ddie, DIE_REF dieref, Execfile *exec );static void freedieinfo( struct dieinfo *di, Execfile *exec );static void completedieinfo(struct dieinfo *, Execfile *exec, int verbose);static void decode_line_numbers(Dwarf_Die, VA *, VA *, Execfile *exec);static VA locval (Dwarf_Locdesc *);static VAlookup_line ( Srcfile *src, Execfile *exec, Dwarf_Unsigned targetline ){ struct dieinfo di; int err; Dwarf_Line *linebuf; Dwarf_Unsigned lineno; Dwarf_Unsigned bestlineno; Dwarf_Addr lineaddr; Dwarf_Addr bestlineaddr; Dwarf_Signed cnt; Dwarf_Error rc; int i; bestlineno = ~0; bestlineaddr = 0; basicdieinfo (&di, NULL, src->dieref, exec); err = dwarf_srclines( di.ddie, &linebuf, &cnt, &rc ); freedieinfo(&di,exec); if( err == DW_DLV_ERROR ) { CPUWarning("dwarf_srclines failed: %s\n", dwarf_errmsg( rc ) ); ASSERT(0); } else if( err == DW_DLV_OK ) { for( i = 0; i < cnt; i++ ) { if( dwarf_lineno( linebuf[i], &lineno, &rc ) != DW_DLV_OK) { CPUWarning("dwarf_lineno failed: %s\n", dwarf_errmsg( rc ) ); exit(-1); } if( dwarf_lineaddr( linebuf[i], &lineaddr, &rc) != DW_DLV_OK) { CPUWarning("dwarf_lineaddr failed: %s\n", dwarf_errmsg( rc ) ); exit(-1); } if( (lineno <= bestlineno) && (lineno >= targetline) ) { /* It doesn't seem like there is an easy way to deal with * line numbers of other files included in this file, such * as inlined source in .h's and that sort of thing. The * best thing may be just to ignore line number info for * file other than our own */ char *name; if( dwarf_linesrc( linebuf[i], &name, &rc) != DW_DLV_OK) { CPUWarning("dwarf_linesrc failed: %s\n", dwarf_errmsg(rc)); exit(-1); } if( strcmp( src->head.label, StripPath(name) ) == 0 ) { bestlineno = lineno; bestlineaddr = lineaddr; } dwarf_dealloc( exec->dwarf, name, DW_DLA_STRING ); } dwarf_dealloc( exec->dwarf, linebuf[i], DW_DLA_LINE ); } dwarf_dealloc( exec->dwarf, linebuf, DW_DLA_LIST ); } return bestlineaddr;}static voiddecode_line_numbers ( Dwarf_Die ddie, VA *lopc, VA *hipc, Execfile *exec ){ int err; Dwarf_Line *linebuf; Dwarf_Unsigned lineno; Dwarf_Addr lineaddr; Dwarf_Signed cnt; Dwarf_Error rc; int i; VA lo, hi; hi = 0; lo = ~hi; err = dwarf_srclines( ddie, &linebuf, &cnt, &rc ); if( err == DW_DLV_ERROR ) { CPUWarning("dwarf_srclines failed: %s\n", dwarf_errmsg( rc ) ); } else if( err == DW_DLV_OK ) { for( i = 0; i < cnt; i++ ) { if( dwarf_lineno( linebuf[i], &lineno, &rc ) != DW_DLV_OK) { CPUWarning("dwarf_lineno failed: %s\n", dwarf_errmsg( rc ) ); exit(-1); } if( dwarf_lineaddr( linebuf[i], &lineaddr, &rc) != DW_DLV_OK) { CPUWarning("dwarf_lineaddr failed: %s\n", dwarf_errmsg( rc ) ); exit(-1); } /* double purpose function: either record line numbers, or find low * and high pc values. We can't do both because we need pc values * before it appears safe to record line numbers. */ if( lopc == NULL ) { /* we don't use this feature yet */ ASSERT(0);#if 0 /* It doesn't seem like there is an easy way to deal with * line numbers of other files included in this file, such * as inlined source in .h's and that sort of thing. The * best thing may be just to ignore line number info for * file other than our own */ char *name; if( dwarf_linesrc( linebuf[i], &name, &rc) != DW_DLV_OK) { CPUWarning("dwarf_linesrc failed: %s\n", dwarf_errmsg(rc)); exit(-1); } if( !strcmp( current_subfile->name, name ) ) { record_line (current_subfile, lineno, lineaddr); } dwarf_dealloc( dwarf, name, DW_DLA_STRING );#endif } else { if( lineaddr < lo ) lo = lineaddr; if( lineaddr > hi ) hi = lineaddr; } dwarf_dealloc( exec->dwarf, linebuf[i], DW_DLA_LINE ); } dwarf_dealloc( exec->dwarf, linebuf, DW_DLA_LIST ); } if( lopc != NULL ) *lopc = lo; if( hipc != NULL ) *hipc = hi;}static VAlocval ( Dwarf_Locdesc *loc ){ VA stack[64]; int stacki; int loc_atom_code; int i; Dwarf_Loc *locs; int numlocs; stacki = 0; stack[stacki] = 0;/* isreg = 0; *//* offreg = 0; */ locs = loc->ld_s; numlocs = loc->ld_cents; for( i = 0; i < numlocs; i++ ) { loc_atom_code = locs[i].lr_atom; switch (loc_atom_code) { case DW_OP_addr: /* push address (relocated address) */ stack[++stacki] = locs[i].lr_number; break; case DW_OP_consts: stack[++stacki] = locs[i].lr_number; break; case DW_OP_fbreg:#if 1#if 0 offreg = 1; basereg = 29; /* FIXME: MIPS stack pointer hard coded */#endif#endif stack[++stacki] = locs[i].lr_number; break; default: CPUWarning("Unimplemented location atom: %x\n", loc_atom_code); break; } } return (stack[stacki]);}static DIE_REFGetTypeAbsOffset( Dwarf_Die ddie, Execfile *exec ){ Dwarf_Attribute attr; Dwarf_Off type, abs, rel; Dwarf_Error rc; if (dwarf_attr(ddie,DW_AT_type,&attr,&rc) != DW_DLV_OK) { return 0; } if( dwarf_formref( attr, &type, &rc ) != DW_DLV_OK) { CPUWarning("dwarf_formref failed: %s\n", dwarf_errmsg( rc ) ); ASSERT(0); } dwarf_dealloc( exec->dwarf, attr, DW_DLA_ATTR); if( dwarf_dieoffset( ddie, &abs, &rc ) != DW_DLV_OK) { CPUWarning("dwarf_dieoffset failed: %s\n", dwarf_errmsg( rc ) ); ASSERT(0); } if( dwarf_die_CU_offset( ddie, &rel, &rc ) != DW_DLV_OK) { CPUWarning("dwarf_die_CU_offset failed: %s\n", dwarf_errmsg( rc ) ); ASSERT(0); } /* convert from cu-relative to absolute offset */ return (abs - rel) + type;}static VAGetLocation( Dwarf_Die ddie, Execfile *exec ){ Dwarf_Error rc; int err; Dwarf_Locdesc *loclist; Dwarf_Signed signedtmp; Dwarf_Attribute attr; VA location; if (dwarf_attr(ddie,DW_AT_location,&attr,&rc) != DW_DLV_OK) { /* try member location */ if (dwarf_attr(ddie,DW_AT_data_member_location,&attr,&rc)!=DW_DLV_OK) { CPUWarning("no location list: %s\n", dwarf_errmsg( rc ) ); ASSERT(0); } } dwarf_loclist( attr, &loclist, &signedtmp, &rc ); if( signedtmp != 1 ) { CPUWarning("location list size %lld != 1\n", signedtmp ); ASSERT(0); } location = locval(loclist); dwarf_dealloc( exec->dwarf, loclist, DW_DLA_LOCDESC); dwarf_dealloc( exec->dwarf, attr, DW_DLA_ATTR); return location;}static intadd_global(struct dieinfo *di, AssocTab *tab){ Global *global; global = (Global*)malloc(sizeof(Global)); global->head.label = SaveString(di->at_name); global->dieref = di->die_ref; global->dietag = di->die_tag; return AssocTabEnter(tab, (ATHeader*)global);}/* release resources associated with die; not all are currently handled */static voidfreedieinfo( struct dieinfo *di, Execfile *exec ){ if( di->ddie ) dwarf_dealloc( exec->dwarf, di->ddie, DW_DLA_DIE ); if( di->sibdie ) dwarf_dealloc( exec->dwarf, di->sibdie, DW_DLA_DIE ); if( di->childdie ) dwarf_dealloc( exec->dwarf, di->childdie, DW_DLA_DIE ); if( di->at_name ) dwarf_dealloc( exec->dwarf, di->at_name, DW_DLA_STRING );}static voidFillInBasicType( Symb *sym, Dwarf_Die ddie, Dwarf_Unsigned *bitsize, Execfile *exec ){ Dwarf_Attribute attr; Dwarf_Unsigned encoding, bytesize; Dwarf_Off type; Dwarf_Error rc; struct dieinfo di; type = GetTypeAbsOffset( ddie, exec ); if( type == 0 ) { /* no type, so do nothing */ return; } basicdieinfo (&di, NULL, type, exec); ddie = di.ddie; switch (di.die_tag) { case DW_TAG_base_type: /* for this we need the size and encoding to translate it to a * form that simos expects */ if( dwarf_bytesize( ddie, &bytesize, &rc ) != DW_DLV_OK) { CPUWarning("dwarf_bytesize failed: %s\n", dwarf_errmsg( rc ) ); ASSERT(0); } *bitsize = 8*bytesize; if (dwarf_attr(ddie,DW_AT_encoding,&attr,&rc) != DW_DLV_OK) { CPUWarning("dwarf_attr for type failed: %s\n", dwarf_errmsg(rc)); ASSERT(0); } if( dwarf_formudata( attr, &encoding, &rc ) != DW_DLV_OK) { CPUWarning("dwarf_formref failed: %s\n", dwarf_errmsg( rc ) ); ASSERT(0); } dwarf_dealloc( exec->dwarf, attr, DW_DLA_ATTR); switch( encoding ) { case DW_ATE_float: switch( bytesize ) { case 4: sym->type[sym->nextt++] = tFloat; break; case 8: sym->type[sym->nextt++] = tDouble; break; default: ASSERT(0); break; } break; case DW_ATE_signed:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -