mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Show backtrace with .debug_info
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@65007 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
139f0bb44f
commit
37ea0f19a7
1 changed files with 630 additions and 335 deletions
583
addr2line.c
583
addr2line.c
|
@ -113,7 +113,7 @@ void *alloca();
|
|||
|
||||
PRINTF_ARGS(static int kprintf(const char *fmt, ...), 1, 2);
|
||||
|
||||
typedef struct {
|
||||
typedef struct line_info {
|
||||
const char *dirname;
|
||||
const char *filename;
|
||||
const char *path; /* object path */
|
||||
|
@ -122,6 +122,8 @@ typedef struct {
|
|||
uintptr_t base_addr;
|
||||
uintptr_t saddr;
|
||||
const char *sname; /* function name */
|
||||
|
||||
struct line_info *next;
|
||||
} line_info_t;
|
||||
typedef struct obj_info obj_info_t;
|
||||
struct obj_info {
|
||||
|
@ -194,8 +196,7 @@ get_nth_dirname(unsigned long dir, char *p)
|
|||
}
|
||||
|
||||
static void
|
||||
fill_filename(int file, char *include_directories, char *filenames,
|
||||
line_info_t *line)
|
||||
fill_filename(int file, char *include_directories, char *filenames, line_info_t *line)
|
||||
{
|
||||
int i;
|
||||
char *p = filenames;
|
||||
|
@ -522,11 +523,18 @@ fail:
|
|||
|
||||
void hexdump0(const unsigned char *p, size_t n) {
|
||||
size_t i;
|
||||
fprintf(stderr, " 0 1 2 3 4 5 6 7 8 9 A B C D E F\n");
|
||||
for (i=0; i < n; i++){
|
||||
if ((i & 15) != 15) {
|
||||
fprintf(stderr, "%02X ", p[i]);
|
||||
} else {
|
||||
switch (i & 15) {
|
||||
case 0:
|
||||
fprintf(stderr, "%02zd: %02X ", i/16, p[i]);
|
||||
break;
|
||||
case 15:
|
||||
fprintf(stderr, "%02X\n", p[i]);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "%02X ", p[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ((i & 15) != 15) {
|
||||
|
@ -535,6 +543,12 @@ void hexdump0(const unsigned char *p, size_t n) {
|
|||
}
|
||||
#define hexdump(p,n) hexdump0((const unsigned char *)p, n)
|
||||
|
||||
enum
|
||||
{
|
||||
DW_TAG_inlined_subroutine = 0x1d,
|
||||
DW_TAG_subprogram = 0x2e,
|
||||
};
|
||||
|
||||
/* Attributes encodings */
|
||||
enum
|
||||
{
|
||||
|
@ -731,6 +745,14 @@ enum
|
|||
DW_FORM_addrx4 = 0x2c
|
||||
};
|
||||
|
||||
enum {
|
||||
VAL_none = 0,
|
||||
VAL_cstr = 1,
|
||||
VAL_data = 2,
|
||||
VAL_uint = 3,
|
||||
VAL_int = 4
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint32_t unit_length;
|
||||
uint16_t version;
|
||||
|
@ -747,25 +769,44 @@ typedef struct {
|
|||
} __attribute__((packed)) DW_CompilationUnitHeader64;
|
||||
|
||||
typedef struct {
|
||||
char *file;
|
||||
ElfW(Shdr) *abbrev;
|
||||
ElfW(Shdr) *info;
|
||||
ElfW(Shdr) *ranges;
|
||||
ElfW(Shdr) *str;
|
||||
ElfW(Shdr) *line;
|
||||
} dwarf_args;
|
||||
|
||||
typedef struct {
|
||||
dwarf_args *dwarf;
|
||||
obj_info_t *obj;
|
||||
char *file;
|
||||
char *current_cu;
|
||||
char *debug_line_cu_end;
|
||||
char *debug_line_files;
|
||||
char *debug_line_directories;
|
||||
char *p0;
|
||||
char *p;
|
||||
char *pend;
|
||||
ElfW(Shdr) *abbrev;
|
||||
char *q0;
|
||||
char *q;
|
||||
ElfW(Shdr) *str;
|
||||
int format; /* 32 or 64 */;
|
||||
uint8_t address_size;
|
||||
int level;
|
||||
} DebugInfoReader;
|
||||
|
||||
typedef struct {
|
||||
int tag;
|
||||
int has_children;
|
||||
} DIE;
|
||||
|
||||
typedef struct {
|
||||
union {
|
||||
char *ptr;
|
||||
uint64_t uint64;
|
||||
int64_t int64;
|
||||
} as;
|
||||
uint64_t at;
|
||||
uint64_t form;
|
||||
size_t size;
|
||||
int type;
|
||||
} DebugInfoValue;
|
||||
|
@ -842,64 +883,107 @@ read_sleb128(DebugInfoReader *reader)
|
|||
return sleb128(&reader->p);
|
||||
}
|
||||
|
||||
static DebugInfoReader *
|
||||
debug_info_reader_new(char *file, ElfW(Shdr) *debug_info_shdr, ElfW(Shdr) *debug_abbrev_shdr, ElfW(Shdr) *debug_str_shdr)
|
||||
static void
|
||||
debug_info_reader_init(DebugInfoReader *reader, obj_info_t *obj, dwarf_args *dwarf)
|
||||
{
|
||||
DebugInfoReader *p = malloc(sizeof(DebugInfoReader));
|
||||
p->file = file;
|
||||
p->info = debug_info_shdr;
|
||||
p->abbrev = debug_abbrev_shdr;
|
||||
p->str = debug_str_shdr;
|
||||
p->p0 = p->p = p->file + debug_info_shdr->sh_offset;
|
||||
p->pend = p->file + debug_info_shdr->sh_offset + debug_info_shdr->sh_size;
|
||||
return p;
|
||||
reader->file = obj->mapped;
|
||||
reader->obj = obj;
|
||||
reader->dwarf = dwarf;
|
||||
reader->p0 = reader->p = reader->file + dwarf->info->sh_offset;
|
||||
reader->pend = reader->file + dwarf->info->sh_offset + dwarf->info->sh_size;
|
||||
reader->debug_line_cu_end = reader->file + dwarf->line->sh_offset;
|
||||
}
|
||||
|
||||
static void
|
||||
debug_info_reader_read_cu(DebugInfoReader *reader)
|
||||
di_read_debug_line_cu(DebugInfoReader *reader)
|
||||
{
|
||||
char *p;
|
||||
unsigned long unit_length;
|
||||
unsigned int opcode_base;
|
||||
|
||||
p = reader->debug_line_cu_end;
|
||||
|
||||
unit_length = *(unsigned int *)p;
|
||||
p += sizeof(unsigned int);
|
||||
if (unit_length == 0xffffffff) {
|
||||
unit_length = *(unsigned long *)p;
|
||||
p += sizeof(unsigned long);
|
||||
}
|
||||
|
||||
reader->debug_line_cu_end = p + unit_length;
|
||||
p += 2;
|
||||
p += sizeof(unsigned int);
|
||||
p += 4;
|
||||
opcode_base = *(unsigned char *)p++;
|
||||
|
||||
/* standard_opcode_lengths = (unsigned char *)p - 1; */
|
||||
p += opcode_base - 1;
|
||||
|
||||
reader->debug_line_directories = p;
|
||||
|
||||
/* skip include directories */
|
||||
while (*p) {
|
||||
p = memchr(p, '\0', reader->debug_line_cu_end - p);
|
||||
if (!p) {
|
||||
fprintf(stderr, "Wrongly reached the end of Directory Table at %tx",
|
||||
reader->debug_line_directories - (reader->file + reader->dwarf->line->sh_offset));
|
||||
abort();
|
||||
}
|
||||
p++;
|
||||
}
|
||||
p++;
|
||||
reader->debug_line_files = p;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
di_read_cu(DebugInfoReader *reader)
|
||||
{
|
||||
DW_CompilationUnitHeader32 *hdr32 = (DW_CompilationUnitHeader32 *)reader->p;
|
||||
reader->current_cu = reader->p;
|
||||
if (hdr32->unit_length == 0xffffffff) {
|
||||
DW_CompilationUnitHeader64 *hdr = (DW_CompilationUnitHeader64 *)hdr32;
|
||||
reader->p += 23;
|
||||
reader->q0 = reader->file + reader->abbrev->sh_offset + hdr->debug_abbrev_offset;
|
||||
reader->q0 = reader->file + reader->dwarf->abbrev->sh_offset + hdr->debug_abbrev_offset;
|
||||
reader->address_size = hdr->address_size;
|
||||
reader->format = 64;
|
||||
} else {
|
||||
DW_CompilationUnitHeader32 *hdr = hdr32;
|
||||
reader->p += 11;
|
||||
reader->q0 = reader->file + reader->abbrev->sh_offset + hdr->debug_abbrev_offset;
|
||||
reader->q0 = reader->file + reader->dwarf->abbrev->sh_offset + hdr->debug_abbrev_offset;
|
||||
reader->address_size = hdr->address_size;
|
||||
reader->format = 32;
|
||||
}
|
||||
reader->level = 0;
|
||||
di_read_debug_line_cu(reader);
|
||||
}
|
||||
|
||||
static void
|
||||
set_uint_value(DebugInfoValue *v, uint64_t n)
|
||||
{
|
||||
v->as.uint64 = n;
|
||||
v->type = 1;
|
||||
v->type = VAL_uint;
|
||||
}
|
||||
|
||||
static void
|
||||
set_sint_value(DebugInfoValue *v, int64_t n)
|
||||
set_int_value(DebugInfoValue *v, int64_t n)
|
||||
{
|
||||
v->as.uint64 = (uint64_t)n;
|
||||
v->type = 2;
|
||||
v->as.int64 = n;
|
||||
v->type = VAL_int;
|
||||
}
|
||||
|
||||
static void
|
||||
set_cstr_value(DebugInfoValue *v, char *s)
|
||||
{
|
||||
v->as.ptr = s;
|
||||
v->type = 3;
|
||||
v->type = VAL_cstr;
|
||||
}
|
||||
|
||||
static void
|
||||
set_bytes_value(DebugInfoValue *v, char *s)
|
||||
set_data_value(DebugInfoValue *v, char *s)
|
||||
{
|
||||
v->as.ptr = s;
|
||||
v->type = 4;
|
||||
v->type = VAL_data;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -907,7 +991,6 @@ debug_info_reader_read_value(DebugInfoReader *reader, uint64_t form, DebugInfoVa
|
|||
{
|
||||
switch (form) {
|
||||
case DW_FORM_addr:
|
||||
fprintf(stderr, "%d: %d\n", __LINE__, reader->address_size);
|
||||
if (reader->address_size == 4) {
|
||||
set_uint_value(v, read_uint32(&reader->p));
|
||||
} else if (reader->address_size == 8) {
|
||||
|
@ -919,12 +1002,12 @@ debug_info_reader_read_value(DebugInfoReader *reader, uint64_t form, DebugInfoVa
|
|||
break;
|
||||
case DW_FORM_block2:
|
||||
v->size = read_uint16(&reader->p);
|
||||
set_bytes_value(v, reader->p);
|
||||
set_data_value(v, reader->p);
|
||||
reader->p += v->size;
|
||||
break;
|
||||
case DW_FORM_block4:
|
||||
v->size = read_uint32(&reader->p);
|
||||
set_bytes_value(v, reader->p);
|
||||
set_data_value(v, reader->p);
|
||||
reader->p += v->size;
|
||||
break;
|
||||
case DW_FORM_data2:
|
||||
|
@ -943,12 +1026,12 @@ debug_info_reader_read_value(DebugInfoReader *reader, uint64_t form, DebugInfoVa
|
|||
break;
|
||||
case DW_FORM_block:
|
||||
v->size = uleb128(&reader->p);
|
||||
set_bytes_value(v, reader->p);
|
||||
set_data_value(v, reader->p);
|
||||
reader->p += v->size;
|
||||
break;
|
||||
case DW_FORM_block1:
|
||||
v->size = read_uint8(&reader->p);
|
||||
set_bytes_value(v, reader->p);
|
||||
set_data_value(v, reader->p);
|
||||
reader->p += v->size;
|
||||
break;
|
||||
case DW_FORM_data1:
|
||||
|
@ -958,10 +1041,10 @@ debug_info_reader_read_value(DebugInfoReader *reader, uint64_t form, DebugInfoVa
|
|||
set_uint_value(v, read_uint8(&reader->p));
|
||||
break;
|
||||
case DW_FORM_sdata:
|
||||
set_sint_value(v, read_sleb128(reader));
|
||||
set_int_value(v, read_sleb128(reader));
|
||||
break;
|
||||
case DW_FORM_strp:
|
||||
set_cstr_value(v, reader->file + reader->str->sh_offset + read_uint(reader));
|
||||
set_cstr_value(v, reader->file + reader->dwarf->str->sh_offset + read_uint(reader));
|
||||
break;
|
||||
case DW_FORM_udata:
|
||||
set_uint_value(v, read_uleb128(reader));
|
||||
|
@ -1000,8 +1083,7 @@ debug_info_reader_read_value(DebugInfoReader *reader, uint64_t form, DebugInfoVa
|
|||
break;
|
||||
case DW_FORM_exprloc:
|
||||
v->size = read_uleb128(reader);
|
||||
set_bytes_value(v, reader->p);
|
||||
hexdump(reader->p, v->size);
|
||||
set_data_value(v, reader->p);
|
||||
reader->p += v->size;
|
||||
break;
|
||||
case DW_FORM_flag_present:
|
||||
|
@ -1077,70 +1159,284 @@ debug_info_reader_read_value(DebugInfoReader *reader, uint64_t form, DebugInfoVa
|
|||
exit(1);
|
||||
}
|
||||
|
||||
static void
|
||||
debug_info_read(DebugInfoReader *reader) {
|
||||
reader->level = 0;
|
||||
for (;;) {
|
||||
uint64_t abbrev_number = uleb128(&reader->p);
|
||||
char has_children;
|
||||
fprintf(stderr,"\n\n%d: <%d> Abbrev Number: %lu\n",__LINE__,reader->level,abbrev_number);
|
||||
if (abbrev_number == 0) {
|
||||
if (reader->level == 1) {
|
||||
return;
|
||||
}
|
||||
reader->level--;
|
||||
continue;
|
||||
}
|
||||
|
||||
reader->q = reader->q0;
|
||||
|
||||
/* find abbrev */
|
||||
for (uint64_t n = uleb128(&reader->q); abbrev_number != n; n = uleb128(&reader->q)) {
|
||||
static char *
|
||||
find_abbrev(char *p, uint64_t abbrev_number) {
|
||||
for (uint64_t n = uleb128(&p); abbrev_number != n; n = uleb128(&p)) {
|
||||
if (n == 0) {
|
||||
fprintf(stderr,"%d: Abbrev Number not found\n",__LINE__);
|
||||
abort();
|
||||
fprintf(stderr,"%d: Abbrev Number %ld not found\n",__LINE__, abbrev_number);
|
||||
exit(1);
|
||||
}
|
||||
/* fprintf(stderr,"%d: %lu != %lu\n",__LINE__, abbrev_number, n); */
|
||||
uleb128(&reader->q); /* tag */
|
||||
reader->q++; /* children */
|
||||
uleb128(&p); /* tag */
|
||||
p++; /* has_children */
|
||||
/* skip content */
|
||||
for (;;) {
|
||||
uint64_t at = uleb128(&reader->q);
|
||||
uint64_t form = uleb128(&reader->q);
|
||||
uint64_t at = uleb128(&p);
|
||||
uint64_t form = uleb128(&p);
|
||||
if (!at && !form) break;
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
uleb128(&reader->q); /* tag */
|
||||
has_children = *reader->q++; /* has_children */
|
||||
if (has_children) {
|
||||
#if 0
|
||||
static void
|
||||
div_inspect(DebugInfoValue *v) {
|
||||
switch (v->type) {
|
||||
case VAL_uint:
|
||||
fprintf(stderr,"%d: type:%d size:%zx v:%lx\n",__LINE__,v->type,v->size,v->as.uint64);
|
||||
break;
|
||||
case VAL_int:
|
||||
fprintf(stderr,"%d: type:%d size:%zx v:%ld\n",__LINE__,v->type,v->size,(int64_t)v->as.uint64);
|
||||
break;
|
||||
case VAL_cstr:
|
||||
fprintf(stderr,"%d: type:%d size:%zx v:'%s'\n",__LINE__,v->type,v->size,v->as.ptr);
|
||||
break;
|
||||
case VAL_data:
|
||||
fprintf(stderr,"%d: type:%d size:%zx v:\n",__LINE__,v->type,v->size);
|
||||
hexdump(v->as.ptr, 16);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static DIE *
|
||||
di_read_die(DebugInfoReader *reader, DIE *die) {
|
||||
uint64_t abbrev_number = uleb128(&reader->p);
|
||||
if (abbrev_number == 0) {
|
||||
reader->level--;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
reader->q = find_abbrev(reader->q0, abbrev_number);
|
||||
|
||||
die->tag = uleb128(&reader->q); /* tag */
|
||||
die->has_children = *reader->q++; /* has_children */
|
||||
if (die->has_children) {
|
||||
reader->level++;
|
||||
}
|
||||
return die;
|
||||
}
|
||||
|
||||
static DebugInfoValue *
|
||||
di_read_record(DebugInfoReader *reader, DebugInfoValue *vp) {
|
||||
uint64_t at = uleb128(&reader->q);
|
||||
uint64_t form = uleb128(&reader->q);
|
||||
if (!at || !form) return NULL;
|
||||
vp->at = at;
|
||||
vp->form = form;
|
||||
debug_info_reader_read_value(reader, form, vp);
|
||||
return vp;
|
||||
}
|
||||
|
||||
static void
|
||||
di_skip_records(DebugInfoReader *reader) {
|
||||
for (;;) {
|
||||
DebugInfoValue v = {0};
|
||||
uint64_t at = uleb128(&reader->q);
|
||||
uint64_t form = uleb128(&reader->q);
|
||||
if (!at || !form) return;
|
||||
debug_info_reader_read_value(reader, form, &v);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
char *file;
|
||||
uintptr_t debug_ranges_offset;
|
||||
uint64_t low_pc;
|
||||
uint64_t high_pc;
|
||||
uint64_t ranges;
|
||||
bool low_pc_set;
|
||||
bool high_pc_set;
|
||||
bool ranges_set;
|
||||
} ranges_t;
|
||||
|
||||
static void
|
||||
ranges_set_low_pc(ranges_t *ptr, uint64_t low_pc) {
|
||||
ptr->low_pc = low_pc;
|
||||
ptr->low_pc_set = true;
|
||||
}
|
||||
|
||||
static void
|
||||
ranges_set_high_pc(ranges_t *ptr, uint64_t high_pc) {
|
||||
ptr->high_pc = high_pc;
|
||||
ptr->high_pc_set = true;
|
||||
}
|
||||
|
||||
static void
|
||||
ranges_set_ranges(ranges_t *ptr, uint64_t ranges) {
|
||||
ptr->ranges = ranges;
|
||||
ptr->ranges_set = true;
|
||||
}
|
||||
|
||||
static int
|
||||
ranges_include(ranges_t *ptr, uint64_t addr) {
|
||||
if (ptr->high_pc_set) {
|
||||
if (ptr->ranges_set || !ptr->low_pc_set) {
|
||||
exit(1);
|
||||
}
|
||||
if (ptr->low_pc <= addr && addr <= ptr->low_pc + ptr->high_pc) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (ptr->ranges_set) {
|
||||
char *p = ptr->file + ptr->debug_ranges_offset + ptr->ranges;
|
||||
for (;;) {
|
||||
uint64_t from = read_uint64(&p);
|
||||
uint64_t to = read_uint64(&p);
|
||||
if (!from && !to) break;
|
||||
if (from <= addr && addr <= to) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ptr->low_pc_set) {
|
||||
if (ptr->low_pc == addr) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void
|
||||
ranges_inspect(ranges_t *ptr) {
|
||||
if (ptr->high_pc_set) {
|
||||
if (ptr->ranges_set || !ptr->low_pc_set) {
|
||||
fprintf(stderr,"low_pc_set:%d high_pc_set:%d ranges_set:%d\n",ptr->low_pc_set,ptr->high_pc_set,ptr->ranges_set);
|
||||
exit(1);
|
||||
}
|
||||
fprintf(stderr,"low_pc:%lx high_pc:%lx\n",ptr->low_pc,ptr->high_pc);
|
||||
}
|
||||
else if (ptr->ranges_set) {
|
||||
char *p;
|
||||
fprintf(stderr,"low_pc:%lx ranges:%lx\n",ptr->low_pc,ptr->ranges);
|
||||
p = ptr->file + ptr->debug_ranges_offset + ptr->ranges;
|
||||
for (;;) {
|
||||
uint64_t from = read_uint64(&p);
|
||||
uint64_t to = read_uint64(&p);
|
||||
if (!from && !to) break;
|
||||
}
|
||||
}
|
||||
else if (ptr->low_pc_set) {
|
||||
fprintf(stderr,"low_pc:%lx\n",ptr->low_pc);
|
||||
}
|
||||
else {
|
||||
fprintf(stderr,"empty\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
read_abstract_origin(DebugInfoReader *reader, uint64_t abstract_origin, line_info_t *line) {
|
||||
char *p = reader->p;
|
||||
char *q = reader->q;
|
||||
int level = reader->level;
|
||||
DIE die;
|
||||
|
||||
reader->p = reader->current_cu + abstract_origin;
|
||||
if (!di_read_die(reader, &die)) goto finish;
|
||||
|
||||
/* enumerate abbrev */
|
||||
for (;;) {
|
||||
DebugInfoValue v = {0};
|
||||
if (!di_read_record(reader, &v)) break;
|
||||
switch (v.at) {
|
||||
case DW_AT_name:
|
||||
line->sname = v.as.ptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
finish:
|
||||
reader->p = p;
|
||||
reader->q = q;
|
||||
reader->level = level;
|
||||
}
|
||||
|
||||
static void
|
||||
debug_info_read(DebugInfoReader *reader, int num_traces, void **traces,
|
||||
line_info_t *lines, int offset) {
|
||||
do {
|
||||
DIE die;
|
||||
ranges_t ranges = {reader->file, reader->dwarf->ranges->sh_offset};
|
||||
//ptrdiff_t diepos = reader->p - reader->p0;
|
||||
line_info_t line = {0};
|
||||
|
||||
if (!di_read_die(reader, &die)) continue;
|
||||
//fprintf(stderr,"%d:%tx: <%d> Abbrev Number: %lu\n",__LINE__,diepos,reader->level,die.tag);
|
||||
|
||||
if (die.tag != DW_TAG_subprogram && die.tag != DW_TAG_inlined_subroutine) {
|
||||
skip_die:
|
||||
di_skip_records(reader);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* enumerate abbrev */
|
||||
for (;;) {
|
||||
uint64_t at = uleb128(&reader->q);
|
||||
uint64_t form = uleb128(&reader->q);
|
||||
DebugInfoValue v = {0};
|
||||
fprintf(stderr,"\n%d:%lx: AT:%lx FORM:%lx\n",__LINE__,reader->p-reader->p0,at,form);
|
||||
if (!at && !form) break;
|
||||
debug_info_reader_read_value(reader, form, &v);
|
||||
switch (v.type) {
|
||||
case 1:
|
||||
fprintf(stderr,"%d: type:%d size:%zx v:%lx\n",__LINE__,v.type,v.size,v.as.uint64);
|
||||
//ptrdiff_t pos = reader->p - reader->p0;
|
||||
if (!di_read_record(reader, &v)) break;
|
||||
//fprintf(stderr,"\n%d:%tx: AT:%lx FORM:%lx\n",__LINE__,pos,v.at,v.form);
|
||||
//div_inspect(&v);
|
||||
switch (v.at) {
|
||||
case DW_AT_name:
|
||||
line.sname = v.as.ptr;
|
||||
break;
|
||||
case 2:
|
||||
fprintf(stderr,"%d: type:%d size:%zx v:%ld\n",__LINE__,v.type,v.size,(int64_t)v.as.uint64);
|
||||
case DW_AT_call_file:
|
||||
fill_filename(v.as.uint64, reader->debug_line_directories, reader->debug_line_files, &line);
|
||||
break;
|
||||
case 3:
|
||||
fprintf(stderr,"%d: type:%d size:%zx v:'%s'\n",__LINE__,v.type,v.size,v.as.ptr);
|
||||
case DW_AT_call_line:
|
||||
line.line = v.as.uint64;
|
||||
break;
|
||||
case 4:
|
||||
fprintf(stderr,"%d: type:%d size:%zx v:\n",__LINE__,v.type,v.size);
|
||||
hexdump(v.as.ptr, 16);
|
||||
case DW_AT_low_pc:
|
||||
ranges_set_low_pc(&ranges, v.as.uint64);
|
||||
break;
|
||||
case DW_AT_high_pc:
|
||||
ranges_set_high_pc(&ranges, v.as.uint64);
|
||||
break;
|
||||
case DW_AT_declaration:
|
||||
goto skip_die;
|
||||
case DW_AT_inline:
|
||||
/* 1 or 3 */
|
||||
break; // goto skip_die;
|
||||
case DW_AT_abstract_origin:
|
||||
read_abstract_origin(reader, v.as.uint64, &line);
|
||||
break; //goto skip_die;
|
||||
case DW_AT_ranges:
|
||||
ranges_set_ranges(&ranges, v.as.uint64);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* fprintf(stderr,"%d:%tx: %x ",__LINE__,diepos,die.tag); */
|
||||
for (int i=offset; i < num_traces; i++) {
|
||||
uintptr_t addr = (uintptr_t)traces[i];
|
||||
uintptr_t offset = addr - reader->obj->base_addr;
|
||||
if (ranges_include(&ranges, offset)) {
|
||||
//fprintf(stderr, "%d:%tx: %lx %x %s: %s/%s %d\n",__LINE__,diepos,addr, die.tag,line.sname,line.dirname,line.filename,line.line);
|
||||
if (lines[i].path) {
|
||||
line_info_t *lp = malloc(sizeof(line_info_t));
|
||||
memcpy(lp, &lines[i], sizeof(line_info_t));
|
||||
lines[i].next = lp;
|
||||
lp->dirname = line.dirname;
|
||||
lp->filename = line.filename;
|
||||
lp->line = line.line;
|
||||
lp->saddr = 0;
|
||||
}
|
||||
lines[i].path = reader->obj->path;
|
||||
lines[i].base_addr = line.base_addr;
|
||||
lines[i].sname = line.sname;
|
||||
lines[i].saddr = reader->obj->base_addr + ranges.low_pc;
|
||||
}
|
||||
}
|
||||
} while (reader->level > 0);
|
||||
}
|
||||
|
||||
static void print_line0(line_info_t *line, void *address);
|
||||
static void
|
||||
print_line(line_info_t *line, void *address) {
|
||||
print_line0(line, address);
|
||||
if (line->next) {
|
||||
print_line(line->next, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1155,8 +1451,7 @@ fill_lines(int num_traces, void **traces, int check_debuglink,
|
|||
ElfW(Ehdr) *ehdr;
|
||||
ElfW(Shdr) *shdr, *shstr_shdr;
|
||||
ElfW(Shdr) *debug_line_shdr = NULL, *gnu_debuglink_shdr = NULL;
|
||||
ElfW(Shdr) *debug_info_shdr = NULL, *debug_abbrev_shdr = NULL;
|
||||
ElfW(Shdr) *debug_str_shdr = NULL;
|
||||
dwarf_args dwarf = {0};
|
||||
int fd;
|
||||
off_t filesize;
|
||||
char *file;
|
||||
|
@ -1236,51 +1531,27 @@ fill_lines(int num_traces, void **traces, int check_debuglink,
|
|||
compressed_p = true;
|
||||
}
|
||||
debug_line_shdr = shdr + i;
|
||||
dwarf.line = shdr + i;
|
||||
}
|
||||
else if (!strcmp(section_name, ".gnu_debuglink")) {
|
||||
gnu_debuglink_shdr = shdr + i;
|
||||
}
|
||||
else if (!strcmp(section_name, ".debug_info")) {
|
||||
debug_info_shdr = shdr + i;
|
||||
}
|
||||
else if (!strcmp(section_name, ".debug_abbrev")) {
|
||||
debug_abbrev_shdr = shdr + i;
|
||||
dwarf.abbrev = shdr + i;
|
||||
}
|
||||
else if (!strcmp(section_name, ".debug_info")) {
|
||||
dwarf.info = shdr + i;
|
||||
}
|
||||
else if (!strcmp(section_name, ".debug_ranges")) {
|
||||
dwarf.ranges = shdr + i;
|
||||
}
|
||||
else if (!strcmp(section_name, ".debug_str")) {
|
||||
debug_str_shdr = shdr + i;
|
||||
dwarf.str = shdr + i;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (debug_info_shdr) {
|
||||
unsigned char *info = (unsigned char *)(file + debug_info_shdr->sh_offset);
|
||||
size_t info_count = debug_info_shdr->sh_size;
|
||||
fprintf(stderr, "size: %zd\n", info_count);
|
||||
hexdump(info, 11);
|
||||
info += 11;
|
||||
hexdump(info, 11);
|
||||
info += 11;
|
||||
hexdump(info, 32);
|
||||
}
|
||||
if (debug_abbrev_shdr) {
|
||||
unsigned char *abbrev = (unsigned char *)(file + debug_abbrev_shdr->sh_offset);
|
||||
size_t abbrev_count = debug_abbrev_shdr->sh_size;
|
||||
fprintf(stderr, "size: %zd\n", abbrev_count);
|
||||
hexdump(abbrev, 128);
|
||||
}
|
||||
{
|
||||
int i = 0;
|
||||
DebugInfoReader *reader = debug_info_reader_new(file, debug_info_shdr, debug_abbrev_shdr, debug_str_shdr);
|
||||
|
||||
while (reader->p < reader->pend) {
|
||||
fprintf(stderr, "CU[%d]\n", i++);
|
||||
debug_info_reader_read_cu(reader);
|
||||
debug_info_read(reader);
|
||||
}
|
||||
}
|
||||
exit(0);
|
||||
|
||||
if (offset == -1) {
|
||||
/* main executable */
|
||||
offset = 0;
|
||||
|
@ -1312,6 +1583,16 @@ fill_lines(int num_traces, void **traces, int check_debuglink,
|
|||
}
|
||||
}
|
||||
|
||||
if (dwarf.str && dwarf.info && dwarf.line && dwarf.abbrev && dwarf.ranges) {
|
||||
DebugInfoReader reader;
|
||||
debug_info_reader_init(&reader, obj, &dwarf);
|
||||
while (reader.p < reader.pend) {
|
||||
//fprintf(stderr, "%d:%tx: CU[%d]\n", __LINE__, di_pos(&reader), i++);
|
||||
di_read_cu(&reader);
|
||||
debug_info_read(&reader, num_traces, traces, lines, offset);
|
||||
}
|
||||
}
|
||||
|
||||
if (!symtab_shdr) {
|
||||
symtab_shdr = dynsym_shdr;
|
||||
strtab_shdr = dynstr_shdr;
|
||||
|
@ -1330,7 +1611,7 @@ fill_lines(int num_traces, void **traces, int check_debuglink,
|
|||
if (lines[i].line > 0 || d <= 0 || d > (uintptr_t)sym->st_size)
|
||||
continue;
|
||||
/* fill symbol name and addr from .symtab */
|
||||
lines[i].sname = strtab + sym->st_name;
|
||||
if (!lines[i].sname) lines[i].sname = strtab + sym->st_name;
|
||||
lines[i].saddr = saddr;
|
||||
lines[i].path = obj->path;
|
||||
lines[i].base_addr = obj->base_addr;
|
||||
|
@ -1408,6 +1689,43 @@ main_exe_path(void)
|
|||
#undef HAVE_MAIN_EXE_PATH
|
||||
#endif
|
||||
|
||||
static void
|
||||
print_line0(line_info_t *line, void *address) {
|
||||
uintptr_t addr = (uintptr_t)address;
|
||||
uintptr_t d = addr - line->saddr;
|
||||
if (!address) {
|
||||
/* inlined */
|
||||
if (line->dirname && line->dirname[0]) {
|
||||
kprintf("%s(%s) %s/%s:%d\n", line->path, line->sname, line->dirname, line->filename, line->line);
|
||||
}
|
||||
else {
|
||||
kprintf("%s(%s) %s:%d\n", line->path, line->sname, line->filename, line->line);
|
||||
}
|
||||
}
|
||||
else if (!line->path) {
|
||||
kprintf("[0x%lx]\n", addr);
|
||||
}
|
||||
else if (!line->saddr || !line->sname) {
|
||||
kprintf("%s(0x%lx) [0x%lx]\n", line->path, addr-line->base_addr, addr);
|
||||
}
|
||||
else if (line->line <= 0) {
|
||||
kprintf("%s(%s+0x%lx) [0x%lx]\n", line->path, line->sname,
|
||||
d, addr);
|
||||
}
|
||||
else if (!line->filename) {
|
||||
kprintf("%s(%s+0x%lx) [0x%lx] ???:%d\n", line->path, line->sname,
|
||||
d, addr, line->line);
|
||||
}
|
||||
else if (line->dirname && line->dirname[0]) {
|
||||
kprintf("%s(%s+0x%lx) [0x%lx] %s/%s:%d\n", line->path, line->sname,
|
||||
d, addr, line->dirname, line->filename, line->line);
|
||||
}
|
||||
else {
|
||||
kprintf("%s(%s+0x%lx) [0x%lx] %s:%d\n", line->path, line->sname,
|
||||
d, addr, line->filename, line->line);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rb_dump_backtrace_with_lines(int num_traces, void **traces)
|
||||
{
|
||||
|
@ -1469,33 +1787,10 @@ next_line:
|
|||
|
||||
/* output */
|
||||
for (i = 0; i < num_traces; i++) {
|
||||
line_info_t *line = &lines[i];
|
||||
uintptr_t addr = (uintptr_t)traces[i];
|
||||
uintptr_t d = addr - line->saddr;
|
||||
if (!line->path) {
|
||||
kprintf("[0x%lx]\n", addr);
|
||||
}
|
||||
else if (!line->saddr || !line->sname) {
|
||||
kprintf("%s(0x%lx) [0x%lx]\n", line->path, addr-line->base_addr, addr);
|
||||
}
|
||||
else if (line->line <= 0) {
|
||||
kprintf("%s(%s+0x%lx) [0x%lx]\n", line->path, line->sname,
|
||||
d, addr);
|
||||
}
|
||||
else if (!line->filename) {
|
||||
kprintf("%s(%s+0x%lx) [0x%lx] ???:%d\n", line->path, line->sname,
|
||||
d, addr, line->line);
|
||||
}
|
||||
else if (line->dirname && line->dirname[0]) {
|
||||
kprintf("%s(%s+0x%lx) [0x%lx] %s/%s:%d\n", line->path, line->sname,
|
||||
d, addr, line->dirname, line->filename, line->line);
|
||||
}
|
||||
else {
|
||||
kprintf("%s(%s+0x%lx) [0x%lx] %s:%d\n", line->path, line->sname,
|
||||
d, addr, line->filename, line->line);
|
||||
}
|
||||
print_line(&lines[i], traces[i]);
|
||||
|
||||
/* FreeBSD's backtrace may show _start and so on */
|
||||
if (line->sname && strcmp("main", line->sname) == 0)
|
||||
if (lines[i].sname && strcmp("main", lines[i].sname) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue