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
583
addr2line.c
583
addr2line.c
@ -113,7 +113,7 @@ void *alloca();
|
|||||||
|
|
||||||
PRINTF_ARGS(static int kprintf(const char *fmt, ...), 1, 2);
|
PRINTF_ARGS(static int kprintf(const char *fmt, ...), 1, 2);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct line_info {
|
||||||
const char *dirname;
|
const char *dirname;
|
||||||
const char *filename;
|
const char *filename;
|
||||||
const char *path; /* object path */
|
const char *path; /* object path */
|
||||||
@ -122,6 +122,8 @@ typedef struct {
|
|||||||
uintptr_t base_addr;
|
uintptr_t base_addr;
|
||||||
uintptr_t saddr;
|
uintptr_t saddr;
|
||||||
const char *sname; /* function name */
|
const char *sname; /* function name */
|
||||||
|
|
||||||
|
struct line_info *next;
|
||||||
} line_info_t;
|
} line_info_t;
|
||||||
typedef struct obj_info obj_info_t;
|
typedef struct obj_info obj_info_t;
|
||||||
struct obj_info {
|
struct obj_info {
|
||||||
@ -194,8 +196,7 @@ get_nth_dirname(unsigned long dir, char *p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
fill_filename(int file, char *include_directories, char *filenames,
|
fill_filename(int file, char *include_directories, char *filenames, line_info_t *line)
|
||||||
line_info_t *line)
|
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
char *p = filenames;
|
char *p = filenames;
|
||||||
@ -522,11 +523,18 @@ fail:
|
|||||||
|
|
||||||
void hexdump0(const unsigned char *p, size_t n) {
|
void hexdump0(const unsigned char *p, size_t n) {
|
||||||
size_t i;
|
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++){
|
for (i=0; i < n; i++){
|
||||||
if ((i & 15) != 15) {
|
switch (i & 15) {
|
||||||
fprintf(stderr, "%02X ", p[i]);
|
case 0:
|
||||||
} else {
|
fprintf(stderr, "%02zd: %02X ", i/16, p[i]);
|
||||||
|
break;
|
||||||
|
case 15:
|
||||||
fprintf(stderr, "%02X\n", p[i]);
|
fprintf(stderr, "%02X\n", p[i]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "%02X ", p[i]);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((i & 15) != 15) {
|
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)
|
#define hexdump(p,n) hexdump0((const unsigned char *)p, n)
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
DW_TAG_inlined_subroutine = 0x1d,
|
||||||
|
DW_TAG_subprogram = 0x2e,
|
||||||
|
};
|
||||||
|
|
||||||
/* Attributes encodings */
|
/* Attributes encodings */
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
@ -731,6 +745,14 @@ enum
|
|||||||
DW_FORM_addrx4 = 0x2c
|
DW_FORM_addrx4 = 0x2c
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
VAL_none = 0,
|
||||||
|
VAL_cstr = 1,
|
||||||
|
VAL_data = 2,
|
||||||
|
VAL_uint = 3,
|
||||||
|
VAL_int = 4
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t unit_length;
|
uint32_t unit_length;
|
||||||
uint16_t version;
|
uint16_t version;
|
||||||
@ -747,25 +769,44 @@ typedef struct {
|
|||||||
} __attribute__((packed)) DW_CompilationUnitHeader64;
|
} __attribute__((packed)) DW_CompilationUnitHeader64;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char *file;
|
ElfW(Shdr) *abbrev;
|
||||||
ElfW(Shdr) *info;
|
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 *p0;
|
||||||
char *p;
|
char *p;
|
||||||
char *pend;
|
char *pend;
|
||||||
ElfW(Shdr) *abbrev;
|
|
||||||
char *q0;
|
char *q0;
|
||||||
char *q;
|
char *q;
|
||||||
ElfW(Shdr) *str;
|
|
||||||
int format; /* 32 or 64 */;
|
int format; /* 32 or 64 */;
|
||||||
uint8_t address_size;
|
uint8_t address_size;
|
||||||
int level;
|
int level;
|
||||||
} DebugInfoReader;
|
} DebugInfoReader;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int tag;
|
||||||
|
int has_children;
|
||||||
|
} DIE;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
union {
|
union {
|
||||||
char *ptr;
|
char *ptr;
|
||||||
uint64_t uint64;
|
uint64_t uint64;
|
||||||
|
int64_t int64;
|
||||||
} as;
|
} as;
|
||||||
|
uint64_t at;
|
||||||
|
uint64_t form;
|
||||||
size_t size;
|
size_t size;
|
||||||
int type;
|
int type;
|
||||||
} DebugInfoValue;
|
} DebugInfoValue;
|
||||||
@ -842,64 +883,107 @@ read_sleb128(DebugInfoReader *reader)
|
|||||||
return sleb128(&reader->p);
|
return sleb128(&reader->p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static DebugInfoReader *
|
static void
|
||||||
debug_info_reader_new(char *file, ElfW(Shdr) *debug_info_shdr, ElfW(Shdr) *debug_abbrev_shdr, ElfW(Shdr) *debug_str_shdr)
|
debug_info_reader_init(DebugInfoReader *reader, obj_info_t *obj, dwarf_args *dwarf)
|
||||||
{
|
{
|
||||||
DebugInfoReader *p = malloc(sizeof(DebugInfoReader));
|
reader->file = obj->mapped;
|
||||||
p->file = file;
|
reader->obj = obj;
|
||||||
p->info = debug_info_shdr;
|
reader->dwarf = dwarf;
|
||||||
p->abbrev = debug_abbrev_shdr;
|
reader->p0 = reader->p = reader->file + dwarf->info->sh_offset;
|
||||||
p->str = debug_str_shdr;
|
reader->pend = reader->file + dwarf->info->sh_offset + dwarf->info->sh_size;
|
||||||
p->p0 = p->p = p->file + debug_info_shdr->sh_offset;
|
reader->debug_line_cu_end = reader->file + dwarf->line->sh_offset;
|
||||||
p->pend = p->file + debug_info_shdr->sh_offset + debug_info_shdr->sh_size;
|
|
||||||
return p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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;
|
DW_CompilationUnitHeader32 *hdr32 = (DW_CompilationUnitHeader32 *)reader->p;
|
||||||
|
reader->current_cu = reader->p;
|
||||||
if (hdr32->unit_length == 0xffffffff) {
|
if (hdr32->unit_length == 0xffffffff) {
|
||||||
DW_CompilationUnitHeader64 *hdr = (DW_CompilationUnitHeader64 *)hdr32;
|
DW_CompilationUnitHeader64 *hdr = (DW_CompilationUnitHeader64 *)hdr32;
|
||||||
reader->p += 23;
|
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->address_size = hdr->address_size;
|
||||||
reader->format = 64;
|
reader->format = 64;
|
||||||
} else {
|
} else {
|
||||||
DW_CompilationUnitHeader32 *hdr = hdr32;
|
DW_CompilationUnitHeader32 *hdr = hdr32;
|
||||||
reader->p += 11;
|
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->address_size = hdr->address_size;
|
||||||
reader->format = 32;
|
reader->format = 32;
|
||||||
}
|
}
|
||||||
|
reader->level = 0;
|
||||||
|
di_read_debug_line_cu(reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
set_uint_value(DebugInfoValue *v, uint64_t n)
|
set_uint_value(DebugInfoValue *v, uint64_t n)
|
||||||
{
|
{
|
||||||
v->as.uint64 = n;
|
v->as.uint64 = n;
|
||||||
v->type = 1;
|
v->type = VAL_uint;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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->as.int64 = n;
|
||||||
v->type = 2;
|
v->type = VAL_int;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
set_cstr_value(DebugInfoValue *v, char *s)
|
set_cstr_value(DebugInfoValue *v, char *s)
|
||||||
{
|
{
|
||||||
v->as.ptr = s;
|
v->as.ptr = s;
|
||||||
v->type = 3;
|
v->type = VAL_cstr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
set_bytes_value(DebugInfoValue *v, char *s)
|
set_data_value(DebugInfoValue *v, char *s)
|
||||||
{
|
{
|
||||||
v->as.ptr = s;
|
v->as.ptr = s;
|
||||||
v->type = 4;
|
v->type = VAL_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -907,7 +991,6 @@ debug_info_reader_read_value(DebugInfoReader *reader, uint64_t form, DebugInfoVa
|
|||||||
{
|
{
|
||||||
switch (form) {
|
switch (form) {
|
||||||
case DW_FORM_addr:
|
case DW_FORM_addr:
|
||||||
fprintf(stderr, "%d: %d\n", __LINE__, reader->address_size);
|
|
||||||
if (reader->address_size == 4) {
|
if (reader->address_size == 4) {
|
||||||
set_uint_value(v, read_uint32(&reader->p));
|
set_uint_value(v, read_uint32(&reader->p));
|
||||||
} else if (reader->address_size == 8) {
|
} else if (reader->address_size == 8) {
|
||||||
@ -919,12 +1002,12 @@ debug_info_reader_read_value(DebugInfoReader *reader, uint64_t form, DebugInfoVa
|
|||||||
break;
|
break;
|
||||||
case DW_FORM_block2:
|
case DW_FORM_block2:
|
||||||
v->size = read_uint16(&reader->p);
|
v->size = read_uint16(&reader->p);
|
||||||
set_bytes_value(v, reader->p);
|
set_data_value(v, reader->p);
|
||||||
reader->p += v->size;
|
reader->p += v->size;
|
||||||
break;
|
break;
|
||||||
case DW_FORM_block4:
|
case DW_FORM_block4:
|
||||||
v->size = read_uint32(&reader->p);
|
v->size = read_uint32(&reader->p);
|
||||||
set_bytes_value(v, reader->p);
|
set_data_value(v, reader->p);
|
||||||
reader->p += v->size;
|
reader->p += v->size;
|
||||||
break;
|
break;
|
||||||
case DW_FORM_data2:
|
case DW_FORM_data2:
|
||||||
@ -943,12 +1026,12 @@ debug_info_reader_read_value(DebugInfoReader *reader, uint64_t form, DebugInfoVa
|
|||||||
break;
|
break;
|
||||||
case DW_FORM_block:
|
case DW_FORM_block:
|
||||||
v->size = uleb128(&reader->p);
|
v->size = uleb128(&reader->p);
|
||||||
set_bytes_value(v, reader->p);
|
set_data_value(v, reader->p);
|
||||||
reader->p += v->size;
|
reader->p += v->size;
|
||||||
break;
|
break;
|
||||||
case DW_FORM_block1:
|
case DW_FORM_block1:
|
||||||
v->size = read_uint8(&reader->p);
|
v->size = read_uint8(&reader->p);
|
||||||
set_bytes_value(v, reader->p);
|
set_data_value(v, reader->p);
|
||||||
reader->p += v->size;
|
reader->p += v->size;
|
||||||
break;
|
break;
|
||||||
case DW_FORM_data1:
|
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));
|
set_uint_value(v, read_uint8(&reader->p));
|
||||||
break;
|
break;
|
||||||
case DW_FORM_sdata:
|
case DW_FORM_sdata:
|
||||||
set_sint_value(v, read_sleb128(reader));
|
set_int_value(v, read_sleb128(reader));
|
||||||
break;
|
break;
|
||||||
case DW_FORM_strp:
|
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;
|
break;
|
||||||
case DW_FORM_udata:
|
case DW_FORM_udata:
|
||||||
set_uint_value(v, read_uleb128(reader));
|
set_uint_value(v, read_uleb128(reader));
|
||||||
@ -1000,8 +1083,7 @@ debug_info_reader_read_value(DebugInfoReader *reader, uint64_t form, DebugInfoVa
|
|||||||
break;
|
break;
|
||||||
case DW_FORM_exprloc:
|
case DW_FORM_exprloc:
|
||||||
v->size = read_uleb128(reader);
|
v->size = read_uleb128(reader);
|
||||||
set_bytes_value(v, reader->p);
|
set_data_value(v, reader->p);
|
||||||
hexdump(reader->p, v->size);
|
|
||||||
reader->p += v->size;
|
reader->p += v->size;
|
||||||
break;
|
break;
|
||||||
case DW_FORM_flag_present:
|
case DW_FORM_flag_present:
|
||||||
@ -1077,70 +1159,284 @@ debug_info_reader_read_value(DebugInfoReader *reader, uint64_t form, DebugInfoVa
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static char *
|
||||||
debug_info_read(DebugInfoReader *reader) {
|
find_abbrev(char *p, uint64_t abbrev_number) {
|
||||||
reader->level = 0;
|
for (uint64_t n = uleb128(&p); abbrev_number != n; n = uleb128(&p)) {
|
||||||
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)) {
|
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
fprintf(stderr,"%d: Abbrev Number not found\n",__LINE__);
|
fprintf(stderr,"%d: Abbrev Number %ld not found\n",__LINE__, abbrev_number);
|
||||||
abort();
|
exit(1);
|
||||||
}
|
}
|
||||||
/* fprintf(stderr,"%d: %lu != %lu\n",__LINE__, abbrev_number, n); */
|
uleb128(&p); /* tag */
|
||||||
uleb128(&reader->q); /* tag */
|
p++; /* has_children */
|
||||||
reader->q++; /* children */
|
|
||||||
/* skip content */
|
/* skip content */
|
||||||
for (;;) {
|
for (;;) {
|
||||||
uint64_t at = uleb128(&reader->q);
|
uint64_t at = uleb128(&p);
|
||||||
uint64_t form = uleb128(&reader->q);
|
uint64_t form = uleb128(&p);
|
||||||
if (!at && !form) break;
|
if (!at && !form) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
uleb128(&reader->q); /* tag */
|
#if 0
|
||||||
has_children = *reader->q++; /* has_children */
|
static void
|
||||||
if (has_children) {
|
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++;
|
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 */
|
/* enumerate abbrev */
|
||||||
for (;;) {
|
for (;;) {
|
||||||
uint64_t at = uleb128(&reader->q);
|
|
||||||
uint64_t form = uleb128(&reader->q);
|
|
||||||
DebugInfoValue v = {0};
|
DebugInfoValue v = {0};
|
||||||
fprintf(stderr,"\n%d:%lx: AT:%lx FORM:%lx\n",__LINE__,reader->p-reader->p0,at,form);
|
//ptrdiff_t pos = reader->p - reader->p0;
|
||||||
if (!at && !form) break;
|
if (!di_read_record(reader, &v)) break;
|
||||||
debug_info_reader_read_value(reader, form, &v);
|
//fprintf(stderr,"\n%d:%tx: AT:%lx FORM:%lx\n",__LINE__,pos,v.at,v.form);
|
||||||
switch (v.type) {
|
//div_inspect(&v);
|
||||||
case 1:
|
switch (v.at) {
|
||||||
fprintf(stderr,"%d: type:%d size:%zx v:%lx\n",__LINE__,v.type,v.size,v.as.uint64);
|
case DW_AT_name:
|
||||||
|
line.sname = v.as.ptr;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case DW_AT_call_file:
|
||||||
fprintf(stderr,"%d: type:%d size:%zx v:%ld\n",__LINE__,v.type,v.size,(int64_t)v.as.uint64);
|
fill_filename(v.as.uint64, reader->debug_line_directories, reader->debug_line_files, &line);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case DW_AT_call_line:
|
||||||
fprintf(stderr,"%d: type:%d size:%zx v:'%s'\n",__LINE__,v.type,v.size,v.as.ptr);
|
line.line = v.as.uint64;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case DW_AT_low_pc:
|
||||||
fprintf(stderr,"%d: type:%d size:%zx v:\n",__LINE__,v.type,v.size);
|
ranges_set_low_pc(&ranges, v.as.uint64);
|
||||||
hexdump(v.as.ptr, 16);
|
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;
|
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(Ehdr) *ehdr;
|
||||||
ElfW(Shdr) *shdr, *shstr_shdr;
|
ElfW(Shdr) *shdr, *shstr_shdr;
|
||||||
ElfW(Shdr) *debug_line_shdr = NULL, *gnu_debuglink_shdr = NULL;
|
ElfW(Shdr) *debug_line_shdr = NULL, *gnu_debuglink_shdr = NULL;
|
||||||
ElfW(Shdr) *debug_info_shdr = NULL, *debug_abbrev_shdr = NULL;
|
dwarf_args dwarf = {0};
|
||||||
ElfW(Shdr) *debug_str_shdr = NULL;
|
|
||||||
int fd;
|
int fd;
|
||||||
off_t filesize;
|
off_t filesize;
|
||||||
char *file;
|
char *file;
|
||||||
@ -1236,51 +1531,27 @@ fill_lines(int num_traces, void **traces, int check_debuglink,
|
|||||||
compressed_p = true;
|
compressed_p = true;
|
||||||
}
|
}
|
||||||
debug_line_shdr = shdr + i;
|
debug_line_shdr = shdr + i;
|
||||||
|
dwarf.line = shdr + i;
|
||||||
}
|
}
|
||||||
else if (!strcmp(section_name, ".gnu_debuglink")) {
|
else if (!strcmp(section_name, ".gnu_debuglink")) {
|
||||||
gnu_debuglink_shdr = shdr + i;
|
gnu_debuglink_shdr = shdr + i;
|
||||||
}
|
}
|
||||||
else if (!strcmp(section_name, ".debug_info")) {
|
|
||||||
debug_info_shdr = shdr + i;
|
|
||||||
}
|
|
||||||
else if (!strcmp(section_name, ".debug_abbrev")) {
|
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")) {
|
else if (!strcmp(section_name, ".debug_str")) {
|
||||||
debug_str_shdr = shdr + i;
|
dwarf.str = shdr + i;
|
||||||
}
|
}
|
||||||
break;
|
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) {
|
if (offset == -1) {
|
||||||
/* main executable */
|
/* main executable */
|
||||||
offset = 0;
|
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) {
|
if (!symtab_shdr) {
|
||||||
symtab_shdr = dynsym_shdr;
|
symtab_shdr = dynsym_shdr;
|
||||||
strtab_shdr = dynstr_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)
|
if (lines[i].line > 0 || d <= 0 || d > (uintptr_t)sym->st_size)
|
||||||
continue;
|
continue;
|
||||||
/* fill symbol name and addr from .symtab */
|
/* 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].saddr = saddr;
|
||||||
lines[i].path = obj->path;
|
lines[i].path = obj->path;
|
||||||
lines[i].base_addr = obj->base_addr;
|
lines[i].base_addr = obj->base_addr;
|
||||||
@ -1408,6 +1689,43 @@ main_exe_path(void)
|
|||||||
#undef HAVE_MAIN_EXE_PATH
|
#undef HAVE_MAIN_EXE_PATH
|
||||||
#endif
|
#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
|
void
|
||||||
rb_dump_backtrace_with_lines(int num_traces, void **traces)
|
rb_dump_backtrace_with_lines(int num_traces, void **traces)
|
||||||
{
|
{
|
||||||
@ -1469,33 +1787,10 @@ next_line:
|
|||||||
|
|
||||||
/* output */
|
/* output */
|
||||||
for (i = 0; i < num_traces; i++) {
|
for (i = 0; i < num_traces; i++) {
|
||||||
line_info_t *line = &lines[i];
|
print_line(&lines[i], traces[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);
|
|
||||||
}
|
|
||||||
/* FreeBSD's backtrace may show _start and so on */
|
/* 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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user