Update dwarf2 support

tccgen.c:
- add anon support. So tcc_state in tcc works now.
- add function pointer support
- remove DW_FORM_implicit_const from DW_TAG_pointer_type

tccrun.c:
- set initial file name
- correctly use pc in DW_LNE_set_address (see lib/bt-exe.c)
- add DW_LNE_define_file support (even if it is deprecated)

tccelf.c
- do not include debug/test_coverage information for stub functions

lib/bt-exe.c
- use num_callers=-1 to mark dll
This commit is contained in:
herman ten brugge 2022-05-07 06:54:13 +02:00
parent f0df48fcdd
commit 18808e325f
4 changed files with 224 additions and 23 deletions

View file

@ -29,6 +29,7 @@ void __bt_init(rt_context *p, int num_callers)
__rt_error = _rt_error;
set_exception_handler();
} else {
p->num_callers = -1;
p->next = rc->next, rc->next = p;
}
}

View file

@ -1426,6 +1426,19 @@ static void set_local_sym(TCCState *s1, const char *name, Section *s, int offset
}
}
/* avoid generating debug/test_coverage code for stub functions */
static void tcc_compile_string_no_debug(TCCState *s, const char *str)
{
int save_do_debug = s->do_debug;
int save_test_coverage = s->test_coverage;
s->do_debug = 0;
s->test_coverage = 0;
tcc_compile_string(s, str);
s->do_debug = save_do_debug;
s->test_coverage = save_test_coverage;
}
#ifdef CONFIG_TCC_BACKTRACE
static void put_ptr(TCCState *s1, Section *s, int offs, const char *name)
{
@ -1489,7 +1502,7 @@ ST_FUNC void tcc_add_btstub(TCCState *s1)
#endif
cstr_printf(&cstr, "__bt_init(__rt_info,%d);}",
s1->output_type == TCC_OUTPUT_DLL ? 0 : s1->rt_num_callers + 1);
tcc_compile_string(s1, cstr.data);
tcc_compile_string_no_debug(s1, cstr.data);
cstr_free(&cstr);
set_local_sym(s1, &"___rt_info"[!s1->leading_underscore], s, o);
}
@ -1528,7 +1541,7 @@ static void tcc_tcov_add_file(TCCState *s1, const char *filename)
"__attribute__((destructor)) static void __tcov_exit() {"
"__store_test_coverage(__tcov_data);"
"}");
tcc_compile_string(s1, cstr.data);
tcc_compile_string_no_debug(s1, cstr.data);
cstr_free(&cstr);
set_local_sym(s1, &"___tcov_data"[!s1->leading_underscore], tcov_section, 0);
}

204
tccgen.c
View file

@ -187,7 +187,7 @@ static const struct {
{ VT_BYTE | VT_UNSIGNED, 1, DW_ATE_unsigned_char, "unsigned char:t25=r25;0;255;" },
/* boolean type */
{ VT_BOOL, 1, DW_ATE_unsigned_char, "bool:t26=r26;0;255;" },
{ VT_VOID, 1, DW_ATE_void, "void:t27=27" },
{ VT_VOID, 1, DW_ATE_unsigned_char, "void:t27=27" },
};
#define N_DEFAULT_DEBUG (sizeof (default_debug) / sizeof (default_debug[0]))
@ -199,7 +199,14 @@ static struct debug_hash {
Sym *type;
} *debug_hash;
static struct debug_anon_hash {
Sym *type;
int n_debug_type;
int *debug_type;
} *debug_anon_hash;
static int n_debug_hash;
static int n_debug_anon_hash;
static struct debug_info {
int start;
@ -251,7 +258,12 @@ static struct debug_info {
#define DWARF_ABBREV_SUBPROGRAM_EXTERNAL 17
#define DWARF_ABBREV_SUBPROGRAM_STATIC 18
#define DWARF_ABBREV_LEXICAL_BLOCK 19
#define DWARF_ABBREV_SUBROUTINE_TYPE 20
#define DWARF_ABBREV_FORMAL_PARAMETER2 21
/* all entries should have been generated with dwarf_uleb128 except
has_children. All values are currently below 128 so this currently
works. */
static const unsigned char dwarf_abbrev_init[] = {
DWARF_ABBREV_COMPILE_UNIT, DW_TAG_compile_unit, 1,
DW_AT_producer, DW_FORM_strp,
@ -298,7 +310,6 @@ static const unsigned char dwarf_abbrev_init[] = {
0, 0,
DWARF_ABBREV_POINTER, DW_TAG_pointer_type, 0,
DW_AT_byte_size, DW_FORM_data1,
DW_AT_byte_size, DW_FORM_implicit_const, 8,
DW_AT_type, DW_FORM_ref4,
0, 0,
DWARF_ABBREV_ARRAY_TYPE, DW_TAG_array_type, 1,
@ -394,6 +405,13 @@ static const unsigned char dwarf_abbrev_init[] = {
DW_AT_high_pc, DW_FORM_data8,
#endif
0, 0,
DWARF_ABBREV_SUBROUTINE_TYPE, DW_TAG_subroutine_type, 1,
DW_AT_type, DW_FORM_ref4,
DW_AT_sibling, DW_FORM_ref4,
0, 0,
DWARF_ABBREV_FORMAL_PARAMETER2, DW_TAG_formal_parameter, 0,
DW_AT_type, DW_FORM_ref4,
0, 0,
0
};
@ -945,7 +963,9 @@ ST_FUNC void tcc_debug_start(TCCState *s1)
func_ind = -1;
debug_next_type = N_DEFAULT_DEBUG;
debug_hash = NULL;
debug_anon_hash = NULL;
n_debug_hash = 0;
n_debug_anon_hash = 0;
/* we're currently 'including' the <command line> */
tcc_debug_bincl(s1);
}
@ -963,12 +983,35 @@ ST_FUNC void tcc_debug_end(TCCState *s1)
if (!s1->do_debug)
return;
if (s1->dwarf) {
int i;
int i, j;
int start_aranges;
unsigned char *ptr;
int text_size = text_section->data_offset;
/* dwarf_info */
for (i = 0; i < n_debug_anon_hash; i++) {
Sym *t = debug_anon_hash[i].type;
int pos = dwarf_info_section->data_offset;
dwarf_data1(dwarf_info_section,
IS_UNION (t->type.t) ? DWARF_ABBREV_UNION_TYPE
: DWARF_ABBREV_STRUCTURE_TYPE);
dwarf_strp(dwarf_info_section,
(t->v & ~SYM_STRUCT) >= SYM_FIRST_ANOM
? "" : get_tok_str(t->v & ~SYM_STRUCT, NULL));
dwarf_uleb128(dwarf_info_section, 0);
dwarf_uleb128(dwarf_info_section, dwarf_line.cur_file);
dwarf_uleb128(dwarf_info_section, file->line_num);
j = dwarf_info_section->data_offset + 5 - dwarf_info.start;
dwarf_data4(dwarf_info_section, j);
dwarf_data1(dwarf_info_section, 0);
for (j = 0; j < debug_anon_hash[i].n_debug_type; j++)
write32le(dwarf_info_section->data +
debug_anon_hash[i].debug_type[j],
pos - dwarf_info.start);
tcc_free (debug_anon_hash[i].debug_type);
}
tcc_free (debug_anon_hash);
dwarf_data1(dwarf_info_section, 0);
ptr = dwarf_info_section->data + dwarf_info.start;
write32le(ptr, dwarf_info_section->data_offset - dwarf_info.start - 4);
@ -1276,16 +1319,69 @@ static void tcc_debug_stabn(TCCState *s1, int type, int value)
}
}
static int tcc_debug_find(Sym *t)
static int tcc_get_dwarf_info(TCCState *s1, Sym *s);
static int tcc_debug_find(Sym *t, int dwarf)
{
int i;
if (!debug_info && dwarf &&
(t->type.t & VT_BTYPE) == VT_STRUCT && t->c == -1) {
for (i = 0; i < n_debug_anon_hash; i++)
if (t == debug_anon_hash[i].type)
return 0;
debug_anon_hash = (struct debug_anon_hash *)
tcc_realloc (debug_anon_hash,
(n_debug_anon_hash + 1) * sizeof(*debug_anon_hash));
debug_anon_hash[n_debug_anon_hash].n_debug_type = 0;
debug_anon_hash[n_debug_anon_hash].debug_type = NULL;
debug_anon_hash[n_debug_anon_hash++].type = t;
return 0;
}
for (i = 0; i < n_debug_hash; i++)
if (t == debug_hash[i].type)
return debug_hash[i].debug_type;
return -1;
}
static void tcc_debug_check_anon(Sym *t, int debug_type)
{
int i;
if (!debug_info && (t->type.t & VT_BTYPE) == VT_STRUCT && t->type.ref->c == -1)
for (i = 0; i < n_debug_anon_hash; i++)
if (t->type.ref == debug_anon_hash[i].type) {
debug_anon_hash[i].debug_type =
tcc_realloc(debug_anon_hash[i].debug_type,
(debug_anon_hash[i].n_debug_type + 1) * sizeof(int));
debug_anon_hash[i].debug_type[debug_anon_hash[i].n_debug_type++] =
debug_type;
}
}
static void tcc_debug_fix_anon(CType *t)
{
int i, j, debug_type;
TCCState *s1 = tcc_state;
if (!s1->do_debug || !s1->dwarf || debug_info)
return;
if ((t->t & VT_BTYPE) == VT_STRUCT && t->ref->c != -1)
for (i = 0; i < n_debug_anon_hash; i++)
if (t->ref == debug_anon_hash[i].type) {
Sym sym = { .type = *t };
debug_type = tcc_get_dwarf_info(s1, &sym);
for (j = 0; j < debug_anon_hash[i].n_debug_type; j++)
write32le(dwarf_info_section->data +
debug_anon_hash[i].debug_type[j], debug_type);
tcc_free(debug_anon_hash[i].debug_type);
n_debug_anon_hash--;
for (; i < n_debug_anon_hash; i++)
debug_anon_hash[i] = debug_anon_hash[i + 1];
}
}
static int tcc_debug_add(Sym *t, int dwarf)
{
int offset = dwarf ? dwarf_info_section->data_offset : ++debug_next_type;
@ -1331,7 +1427,7 @@ static void tcc_get_debug_info(TCCState *s1, Sym *s, CString *result)
Sym *e = t;
t = t->type.ref;
debug_type = tcc_debug_find(t);
debug_type = tcc_debug_find(t, 0);
if (debug_type == -1) {
debug_type = tcc_debug_add(t, 0);
cstr_new (&str);
@ -1369,7 +1465,7 @@ static void tcc_get_debug_info(TCCState *s1, Sym *s, CString *result)
else if (IS_ENUM(type)) {
Sym *e = t = t->type.ref;
debug_type = tcc_debug_find(t);
debug_type = tcc_debug_find(t, 0);
if (debug_type == -1) {
debug_type = tcc_debug_add(t, 0);
cstr_new (&str);
@ -1430,6 +1526,8 @@ static int tcc_get_dwarf_info(TCCState *s1, Sym *s)
int debug_type = -1;
Sym *e, *t = s;
int i;
int last_pos = -1;
int retval;
for (;;) {
type = t->type.t & ~(VT_STORAGE | VT_CONSTANT | VT_VOLATILE);
@ -1442,7 +1540,7 @@ static int tcc_get_dwarf_info(TCCState *s1, Sym *s)
}
if ((type & VT_BTYPE) == VT_STRUCT) {
t = t->type.ref;
debug_type = tcc_debug_find(t);
debug_type = tcc_debug_find(t, 1);
if (debug_type == -1) {
int pos_sib, i, *pos_type;
@ -1504,6 +1602,7 @@ static int tcc_get_dwarf_info(TCCState *s1, Sym *s)
while (e->next) {
e = e->next;
type = tcc_get_dwarf_info(s1, e);
tcc_debug_check_anon(e, pos_type[i]);
write32le(dwarf_info_section->data + pos_type[i++],
type - dwarf_info.start);
}
@ -1514,7 +1613,7 @@ static int tcc_get_dwarf_info(TCCState *s1, Sym *s)
}
else if (IS_ENUM(type)) {
t = t->type.ref;
debug_type = tcc_debug_find(t);
debug_type = tcc_debug_find(t, 1);
if (debug_type == -1) {
int pos_sib, pos_type;
CType ct = { VT_INT | (type & VT_UNSIGNED) , NULL };
@ -1569,8 +1668,9 @@ static int tcc_get_dwarf_info(TCCState *s1, Sym *s)
*strchr(name, ':') = 0;
dwarf_strp(dwarf_info_section, name);
dwarf_info.base_type_used[i - 1] = debug_type;
}
}
}
retval = debug_type;
t = s;
for (;;) {
type = t->type.t & ~(VT_STORAGE | VT_CONSTANT | VT_VOLATILE);
@ -1578,10 +1678,18 @@ static int tcc_get_dwarf_info(TCCState *s1, Sym *s)
type &= ~VT_DEFSIGN;
if (type == VT_PTR) {
i = dwarf_info_section->data_offset;
if (retval == debug_type)
retval = i;
dwarf_data1(dwarf_info_section, DWARF_ABBREV_POINTER);
dwarf_data1(dwarf_info_section, PTR_SIZE);
dwarf_data4(dwarf_info_section, debug_type - dwarf_info.start);
debug_type = i;
if (last_pos != -1) {
tcc_debug_check_anon(e, last_pos);
write32le(dwarf_info_section->data + last_pos,
i - dwarf_info.start);
}
last_pos = dwarf_info_section->data_offset;
e = t->type.ref;
dwarf_data4(dwarf_info_section, 0);
}
else if (type == (VT_PTR | VT_ARRAY)) {
int sib_pos, sub_type;
@ -1590,8 +1698,17 @@ static int tcc_get_dwarf_info(TCCState *s1, Sym *s)
sub_type = tcc_get_dwarf_info(s1, &sym);
i = dwarf_info_section->data_offset;
if (retval == debug_type)
retval = i;
dwarf_data1(dwarf_info_section, DWARF_ABBREV_ARRAY_TYPE);
dwarf_data4(dwarf_info_section, debug_type - dwarf_info.start);
if (last_pos != -1) {
tcc_debug_check_anon(e, last_pos);
write32le(dwarf_info_section->data + last_pos,
i - dwarf_info.start);
}
last_pos = dwarf_info_section->data_offset;
e = t->type.ref;
dwarf_data4(dwarf_info_section, 0);
sib_pos = dwarf_info_section->data_offset;
dwarf_data4(dwarf_info_section, 0);
for (;;) {
@ -1607,16 +1724,66 @@ static int tcc_get_dwarf_info(TCCState *s1, Sym *s)
dwarf_data1(dwarf_info_section, 0);
write32le(dwarf_info_section->data + sib_pos,
dwarf_info_section->data_offset - dwarf_info.start);
debug_type = i;
}
else if (type == VT_FUNC) {
return tcc_get_dwarf_info (s1, t->type.ref);
int sib_pos, *pos_type;
Sym *f;
i = dwarf_info_section->data_offset;
debug_type = tcc_get_dwarf_info(s1, t->type.ref);
if (retval == debug_type)
retval = i;
dwarf_data1(dwarf_info_section, DWARF_ABBREV_SUBROUTINE_TYPE);
if (last_pos != -1) {
tcc_debug_check_anon(e, last_pos);
write32le(dwarf_info_section->data + last_pos,
i - dwarf_info.start);
}
last_pos = dwarf_info_section->data_offset;
e = t->type.ref;
dwarf_data4(dwarf_info_section, 0);
sib_pos = dwarf_info_section->data_offset;
dwarf_data4(dwarf_info_section, 0);
f = t->type.ref;
i = 0;
while (f->next) {
f = f->next;
i++;
}
pos_type = (int *) tcc_malloc(i * sizeof(int));
f = t->type.ref;
i = 0;
while (f->next) {
f = f->next;
dwarf_data1(dwarf_info_section, DWARF_ABBREV_FORMAL_PARAMETER2);
pos_type[i++] = dwarf_info_section->data_offset;
dwarf_data4(dwarf_info_section, 0);
}
dwarf_data1(dwarf_info_section, 0);
write32le(dwarf_info_section->data + sib_pos,
dwarf_info_section->data_offset - dwarf_info.start);
f = t->type.ref;
i = 0;
while (f->next) {
f = f->next;
type = tcc_get_dwarf_info(s1, f);
tcc_debug_check_anon(f, pos_type[i]);
write32le(dwarf_info_section->data + pos_type[i++],
type - dwarf_info.start);
}
tcc_free(pos_type);
}
else
else {
if (last_pos != -1) {
tcc_debug_check_anon(e, last_pos);
write32le(dwarf_info_section->data + last_pos,
debug_type - dwarf_info.start);
}
break;
}
t = t->type.ref;
}
return debug_type;
return retval;
}
static void tcc_debug_finish (TCCState *s1, struct debug_info *cur)
@ -1787,6 +1954,7 @@ static void tcc_debug_funcend(TCCState *s1, int size)
dwarf_strp(dwarf_info_section, funcname);
dwarf_uleb128(dwarf_info_section, dwarf_line.cur_file);
dwarf_uleb128(dwarf_info_section, dwarf_info.line);
tcc_debug_check_anon(sym->type.ref, dwarf_info_section->data_offset);
dwarf_data4(dwarf_info_section, debug_info - dwarf_info.start);
dwarf_reloc(dwarf_info_section, section_sym, R_DATA_PTR);
#if PTR_SIZE == 4
@ -1843,6 +2011,7 @@ static void tcc_debug_extern_sym(TCCState *s1, Sym *sym, int sh_num, int sym_bin
dwarf_strp(dwarf_info_section, get_tok_str(sym->v, NULL));
dwarf_uleb128(dwarf_info_section, dwarf_line.cur_file);
dwarf_uleb128(dwarf_info_section, file->line_num);
tcc_debug_check_anon(sym, dwarf_info_section->data_offset);
dwarf_data4(dwarf_info_section, debug_type - dwarf_info.start);
if (sym_bind == STB_GLOBAL)
dwarf_data1(dwarf_info_section, 1);
@ -1888,6 +2057,7 @@ static void tcc_debug_typedef(TCCState *s1, Sym *sym)
dwarf_strp(dwarf_info_section, get_tok_str(sym->v & ~SYM_FIELD, NULL));
dwarf_uleb128(dwarf_info_section, dwarf_line.cur_file);
dwarf_uleb128(dwarf_info_section, file->line_num);
tcc_debug_check_anon(sym, dwarf_info_section->data_offset);
dwarf_data4(dwarf_info_section, debug_type - dwarf_info.start);
}
return;
@ -6106,6 +6276,8 @@ do_decl:
check_fields(type, 1);
check_fields(type, 0);
struct_layout(type, &ad);
if (debug_modes)
tcc_debug_fix_anon(type);
}
}
}

View file

@ -754,14 +754,14 @@ next:
}
}
else {
while ((i = DW_GETC(ln, end))) {
while ((DW_GETC(ln, end))) {
#if 0
if (++dir_size < DIR_TABLE_SIZE)
dirs[dir_size - 1] = (char *)ln - 1;
#endif
while (DW_GETC(ln, end)) {}
}
while ((i = DW_GETC(ln, end))) {
while ((DW_GETC(ln, end))) {
if (++filename_size < FILE_TABLE_SIZE) {
filename_table[filename_size - 1].name = (char *)ln - 1;
while (DW_GETC(ln, end)) {}
@ -776,6 +776,8 @@ next:
dwarf_read_uleb128(&ln, end); // size
}
}
if (filename_size >= 2)
filename = filename_table[1].name;
while (ln < end) {
last_pc = pc;
switch (DW_GETC(ln, end)) {
@ -790,14 +792,27 @@ next:
goto next_line;
case DW_LNE_set_address:
#if PTR_SIZE == 4
dwarf_read_32(&cp, end);
pc = dwarf_read_32(&cp, end);
#else
dwarf_read_64(&cp, end);
pc = dwarf_read_64(&cp, end);
#endif
pc = rc->dwarf_text;
if (rc->num_callers < 0)
pc = rc->dwarf_text; /* dll */
opindex = 0;
break;
case DW_LNE_define_file: /* deprecated */
if (++filename_size < FILE_TABLE_SIZE) {
filename_table[filename_size - 1].name = (char *)ln - 1;
while (DW_GETC(ln, end)) {}
filename_table[filename_size - 1].dir_entry =
dwarf_read_uleb128(&ln, end);
}
else {
while (DW_GETC(ln, end)) {}
dwarf_read_uleb128(&ln, end);
}
dwarf_read_uleb128(&ln, end); // time
dwarf_read_uleb128(&ln, end); // size
break;
case DW_LNE_set_discriminator:
dwarf_read_uleb128(&cp, end);