1
0
Fork 0
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:
naruse 2018-10-11 23:55:44 +00:00
parent 139f0bb44f
commit 37ea0f19a7

View file

@ -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;
}