Project

General

Profile

Bug #17585 » ruby-dwarf5-debug_line.patch

xtkoba (Tee KOBAYASHI), 02/10/2021 04:38 PM

View differences:

addr2line.c
struct dwarf_section debug_line;
struct dwarf_section debug_ranges;
struct dwarf_section debug_str;
struct dwarf_section debug_line_str;
struct obj_info *next;
} obj_info_t;
#define DWARF_SECTION_COUNT 5
#define DWARF_SECTION_COUNT 6
static struct dwarf_section *
obj_dwarf_section_at(obj_info_t *obj, int n)
......
&obj->debug_info,
&obj->debug_line,
&obj->debug_ranges,
&obj->debug_str
&obj->debug_str,
&obj->debug_line_str,
};
if (n < 0 || DWARF_SECTION_COUNT <= n) {
abort();
......
return r;
}
static const char *get_nth_dirname_5(unsigned long, uint16_t, uint8_t, uint8_t, obj_info_t *, char *);
static const char *
get_nth_dirname(unsigned long dir, char *p)
get_nth_dirname(unsigned long dir, uint16_t version, uint8_t format, uint8_t address_size, obj_info_t *obj, char *p)
{
if (version >= 5) {
return get_nth_dirname_5(dir, version, format, address_size, obj, p);
}
if (!dir--) {
return "";
}
......
return p;
}
static void fill_filename_5(int, uint16_t, uint8_t, uint8_t, char *, char *, line_info_t *, obj_info_t *);
static void
fill_filename(int file, char *include_directories, char *filenames, line_info_t *line, obj_info_t *obj)
fill_filename(int file, uint16_t version, uint8_t format, uint8_t address_size, char *include_directories, char *filenames, line_info_t *line, obj_info_t *obj)
{
int i;
char *p = filenames;
char *filename;
unsigned long dir;
if (version >= 5) {
fill_filename_5(file, version, format, address_size, include_directories, filenames, line, obj);
return;
}
for (i = 1; i <= file; i++) {
filename = p;
if (!*p) {
......
if (i == file) {
line->filename = filename;
line->dirname = get_nth_dirname(dir, include_directories);
line->dirname = get_nth_dirname(dir, version, format, address_size, obj, include_directories);
}
}
}
static void
fill_line(int num_traces, void **traces, uintptr_t addr, int file, int line,
uint16_t version, uint8_t format, uint8_t address_size,
char *include_directories, char *filenames,
obj_info_t *obj, line_info_t *lines, int offset)
{
......
/* We assume one line code doesn't result >100 bytes of native code.
We may want more reliable way eventually... */
if (addr < a && a < addr + 100) {
fill_filename(file, include_directories, filenames, &lines[i], obj);
fill_filename(file, version, format, address_size, include_directories, filenames, &lines[i], obj);
lines[i].line = line;
}
}
......
uint64_t unit_length;
uint16_t version;
uint8_t format; /* 4 or 8 */
uint8_t address_size;
uint8_t segment_selector_size;
uint64_t header_length;
uint8_t minimum_instruction_length;
uint8_t maximum_operations_per_instruction;
......
const char *cu_end;
};
static int debug_line_header_skip_directories_5(char **, struct LineNumberProgramHeader *);
static int
parse_debug_line_header(const char **pp, struct LineNumberProgramHeader *header)
{
......
header->version = *(uint16_t *)p;
p += sizeof(uint16_t);
if (header->version > 4) return -1;
if (header->version > 5) return -1;
if (header->version >= 5) {
header->address_size = *(uint8_t *)p++;
/* header->segment_selector_size = *(uint8_t *)p; */
if (*p != 0) return -1;
p++;
} else {
header->address_size = 0;
}
header->header_length = header->format == 4 ? *(uint32_t *)p : *(uint64_t *)p;
p += header->format;
......
if (p >= header->cu_end) return -1;
/* skip include directories */
while (*p) {
p = memchr(p, '\0', header->cu_end - p);
if (!p) return -1;
if (header->version >= 5) {
if (debug_line_header_skip_directories_5((char **)&p, header)) return -1;
} else {
while (*p) {
p = memchr(p, '\0', header->cu_end - p);
if (!p) return -1;
p++;
}
p++;
}
p++;
}
header->filenames = p;
......
#define FILL_LINE() \
do { \
fill_line(num_traces, traces, addr, file, line, \
header.version, \
header.format, \
header.address_size, \
(char *)header.include_directories, \
(char *)header.filenames, \
obj, lines, offset); \
......
DW_FORM_addrx4 = 0x2c
};
/* Content type codes */
enum
{
DW_LNCT_path = 0x01,
DW_LNCT_directory_index = 0x02,
DW_LNCT_timestamp = 0x03,
DW_LNCT_size = 0x04,
DW_LNCT_MD5 = 0x05
};
enum {
VAL_none = 0,
VAL_cstr = 1,
......
char *file;
char *current_cu;
uint64_t current_low_pc;
uint16_t debug_line_version;
uint8_t debug_line_format;
uint8_t debug_line_address_size;
char *debug_line_cu_end;
char *debug_line_files;
char *debug_line_directories;
......
if (parse_debug_line_header(&p, &header))
return -1;
reader->debug_line_version = header.version;
reader->debug_line_format = header.format;
reader->debug_line_address_size = header.address_size;
reader->debug_line_cu_end = (char *)header.cu_end;
reader->debug_line_directories = (char *)header.include_directories;
reader->debug_line_files = (char *)header.filenames;
......
static const char *
get_cstr_value(DebugInfoValue *v)
{
if (v->as.ptr) {
return v->as.ptr + v->off;
} else {
return NULL;
switch (v->form) {
case DW_FORM_strp:
if (v->as.ptr) {
return v->as.ptr + v->off;
} else {
return NULL;
}
default:
return NULL;
}
}
......
line.sname = get_cstr_value(&v);
break;
case DW_AT_call_file:
fill_filename((int)v.as.uint64, reader->debug_line_directories, reader->debug_line_files, &line, reader->obj);
fill_filename((int)v.as.uint64, reader->debug_line_version, reader->debug_line_format, reader->debug_line_address_size, reader->debug_line_directories, reader->debug_line_files, &line, reader->obj);
break;
case DW_AT_call_line:
line.line = (int)v.as.uint64;
......
".debug_info",
".debug_line",
".debug_ranges",
".debug_str"
".debug_str",
".debug_line_str",
};
for (j=0; j < DWARF_SECTION_COUNT; j++) {
......
if (di_read_cu(&reader)) goto use_symtab;
debug_info_read(&reader, num_traces, traces, lines, offset);
}
if (reader.debug_line_version >= 5) goto use_symtab;
}
else {
/* This file doesn't have dwarf, use symtab or dynsym */
......
"__debug_info",
"__debug_line",
"__debug_ranges",
"__debug_str"
"__debug_str",
"__debug_line_str",
};
struct LP(segment_command) *scmd = (struct LP(segment_command) *)lcmd;
if (strcmp(scmd->segname, "__TEXT") == 0) {
......
free(dladdr_fbases);
}
static const char *
get_nth_dirname_5(unsigned long dir, uint16_t version, uint8_t format, uint8_t address_size, obj_info_t *obj, char *p)
{
const char *ret = "";
uint64_t i, j;
DebugInfoReader reader = {
.format = format,
.address_size = address_size,
.p = p
};
uint8_t format_count = read_uint8(&reader.p);
uint64_t *content_types = calloc(format_count, sizeof(uint64_t));
uint64_t *forms = calloc(format_count, sizeof(uint64_t));
if (content_types == NULL || forms == NULL) return "";
for (i = 0; i < format_count; ++i) {
content_types[i] = uleb128(&reader.p);
forms[i] = uleb128(&reader.p);
}
uint64_t directories_count = uleb128(&reader.p);
DebugInfoValue v = {{}};
for (j = 0; j < directories_count; ++j) {
for (i = 0; i < format_count; ++i) {
debug_info_reader_read_value(&reader, forms[i], &v);
if (j == dir && content_types[i] == DW_LNCT_path) {
switch (forms[i]) {
case DW_FORM_line_strp:
ret = &obj->debug_line_str.ptr[v.as.uint64];
break;
}
}
}
}
free(forms);
free(content_types);
return ret;
}
static void
fill_filename_5(int file, uint16_t version, uint8_t format, uint8_t address_size, char *include_directories, char *filenames, line_info_t *line, obj_info_t *obj)
{
char *p = filenames;
unsigned long dir;
uint64_t i, j;
DebugInfoReader reader = {
.format = format,
.address_size = address_size,
.p = p
};
uint8_t format_count = read_uint8(&reader.p);
uint64_t *content_types = calloc(format_count, sizeof(uint64_t));
uint64_t *forms = calloc(format_count, sizeof(uint64_t));
if (content_types == NULL || forms == NULL) return;
for (i = 0; i < format_count; ++i) {
content_types[i] = uleb128(&reader.p);
forms[i] = uleb128(&reader.p);
}
uint64_t file_names_count = uleb128(&reader.p);
DebugInfoValue v = {{}};
for (j = 0; j < file_names_count; ++j) {
for (i = 0; i < format_count; ++i) {
debug_info_reader_read_value(&reader, forms[i], &v);
if ((int)j == file) {
switch (content_types[i]) {
case DW_LNCT_path:
switch (forms[i]) {
case DW_FORM_line_strp:
line->filename = &obj->debug_line_str.ptr[v.as.uint64];
break;
}
break;
case DW_LNCT_directory_index:
switch (forms[i]) {
case DW_FORM_udata:
dir = v.as.uint64;
break;
}
break;
}
}
}
}
free(forms);
free(content_types);
line->dirname = get_nth_dirname_5(dir, version, format, address_size, obj, include_directories);
return;
}
static int
debug_line_header_skip_directories_5(char **p, struct LineNumberProgramHeader *header)
{
uint64_t i, j;
DebugInfoReader reader = {
.format = header->format,
.address_size = header->address_size,
.p = *p
};
uint8_t format_count = read_uint8(&reader.p);
uint64_t *forms = calloc(format_count, sizeof(uint64_t));
if (forms == NULL) return -1;
for (i = 0; i < format_count; ++i) {
uleb128(&reader.p); /* content type code */
forms[i] = uleb128(&reader.p);
}
uint64_t directories_count = uleb128(&reader.p);
DebugInfoValue v = {{}};
for (j = 0; j < directories_count; ++j) {
for (i = 0; i < format_count; ++i) {
debug_info_reader_read_value(&reader, forms[i], &v);
}
}
free(forms);
*p = reader.p;
return 0;
}
/* From FreeBSD's lib/libstand/printf.c */
/*-
* Copyright (c) 1986, 1988, 1991, 1993
(2-2/3)