On 2020-01-20 01:37, Michael Matz wrote:
Hello,
On Sat, 18 Jan 2020, Herman ten Brugge via Tinycc-devel wrote:
Oops. Sent the wrong patch. See correct one in attachment.
I created a path to add debug type information (see attachment).
The patch only supports basic types and array/ptr types of them.
It also doesn't deal with scopes, i.e. represents this incorrectly:
int foo (void) {
int i = 1;
float f;
if (i) {
float i = 1.0;
f = i;
}
return i + f;
}
It's still useful, of course, also with the limitation. Some time ago
I approached the debug problem from that angle first before dealing
with types, see attached patch (which makes all variable be int). But
I didn't like the outcome in that it uses a new data structure for the
scopes and the associated book keeping. The difficulty with stabs is
that the variables for a scope need to be emitted directly _before_
the scope-open stab, which really goes against the structure of TCCs
parser, as the open/close stabs still need to form a correct nesting,
so there's no natural place to emit the variable stabs :-/
I updated the patch. It now uses LBRAC/RBRAC. I also fixed some other
minor problems.
I also had to use a new struct to save debugging info. With stabs you
also cannot mix LINE info and SYM info.
With the current patch debugging is a lot easier.
In a followed up patch I will probably add support for
structs/unions/enums/bitfields.
This will take some time. Stabs format is a bit difficult to implement
correctly.
This also has to wait until the end of next month.
Regards,
Herman
diff --git a/tccgen.c b/tccgen.c
index 131f081..8cebdf0 100644
--- a/tccgen.c
+++ b/tccgen.c
@@ -122,6 +122,61 @@ static struct scope {
Sym *lstk, *llstk;
} *cur_scope, *loop_scope, *root_scope;
+static struct {
+ int type;
+ const char *name;
+} default_debug[] = {
+ { VT_INT, "int:t1=r1;-2147483648;2147483647;", },
+ { VT_BYTE, "char:t2=r2;0;127;", },
+#if LONG_SIZE == 4
+ { VT_LONG | VT_INT, "long int:t3=r3;-2147483648;2147483647;", },
+#else
+ { VT_LLONG | VT_LONG, "long
int:t3=r3;-9223372036854775808;9223372036854775807;", },
+#endif
+ { VT_INT | VT_UNSIGNED, "unsigned int:t4=r4;0;4294967295;", },
+#if LONG_SIZE == 4
+ { VT_LONG | VT_INT | VT_UNSIGNED, "long unsigned
int:t5=r5;0;4294967295;", },
+#else
+ { VT_LLONG | VT_LONG | VT_UNSIGNED, "long unsigned int:t5=r5;0;-1;", },
+#endif
+ { VT_QLONG, "__int128:t6=r6;0;-1;", },
+ { VT_QLONG | VT_UNSIGNED, "__int128 unsigned:t7=r7;0;-1;", },
+ { VT_LLONG, "long long
int:t8=r8;-9223372036854775808;9223372036854775807;", },
+ { VT_LLONG | VT_UNSIGNED, "long long unsigned int:t9=r9;0;-1;", },
+ { VT_SHORT, "short int:t10=r10;-32768;32767;", },
+ { VT_SHORT | VT_UNSIGNED, "short unsigned int:t11=r11;0;65535;", },
+ { VT_BYTE | VT_DEFSIGN, "signed char:t12=r12;-128;127;", },
+ { VT_BYTE | VT_DEFSIGN | VT_UNSIGNED, "unsigned char:t13=r13;0;255;", },
+ { VT_FLOAT, "float:t14=r1;4;0;", },
+ { VT_DOUBLE, "double:t15=r1;8;0;", },
+ { VT_LDOUBLE, "long double:t16=r1;16;0;", },
+ { -1, "_Float32:t17=r1;4;0;", },
+ { -1, "_Float64:t18=r1;8;0;", },
+ { -1, "_Float128:t19=r1;16;0;", },
+ { -1, "_Float32x:t20=r1;8;0;", },
+ { -1, "_Float64x:t21=r1;16;0;", },
+ { -1, "_Decimal32:t22=r1;4;0;", },
+ { -1, "_Decimal64:t23=r1;8;0;", },
+ { -1, "_Decimal128:t24=r1;16;0;", },
+ { VT_VOID, "void:t25=25", },
+};
+
+static int debug_next_type = sizeof(default_debug) / sizeof(default_debug[0]);
+
+static struct debug_info {
+ int start;
+ int end;
+ int n_sym;
+ struct debug_sym {
+ int type;
+ unsigned long value;
+ char *str;
+ } *sym;
+ struct debug_info *child, *next, *last, *parent;
+} *debug_info, *debug_info_root;
+
+static CString debug_str;
+
/********************************************************/
#ifndef CONFIG_TCC_ASM
ST_FUNC void asm_instr(void)
@@ -323,6 +378,7 @@ void pv (const char *lbl, int a, int b)
ST_FUNC void tcc_debug_start(TCCState *s1)
{
if (s1->do_debug) {
+ int i;
char buf[512];
/* file info: full path + filename */
@@ -338,6 +394,8 @@ ST_FUNC void tcc_debug_start(TCCState *s1)
text_section->data_offset, text_section, section_sym);
put_stabs_r(s1, file->prev->filename, N_SO, 0, 0,
text_section->data_offset, text_section, section_sym);
+ for (i = 0; i < sizeof (default_debug) / sizeof (default_debug[0]);
i++)
+ put_stabs(s1, default_debug[i].name, N_LSYM, 0, 0, 0);
new_file = last_line_num = 0;
func_ind = -1;
/* we're currently 'including' the <command line> */
@@ -351,6 +409,132 @@ ST_FUNC void tcc_debug_start(TCCState *s1)
SHN_ABS, file->filename);
}
+static void tcc_get_debug_info(Sym *s, CString *result)
+{
+ int i;
+ int n = 0;
+ int type;
+ Sym *t = s;
+
+ for (;;) {
+ type = t->type.t & ~(VT_EXTERN | VT_STATIC | VT_CONSTANT |
VT_VOLATILE);
+ if ((type & VT_BTYPE) != VT_BYTE)
+ type &= ~VT_DEFSIGN;
+ if (type == VT_PTR || type == (VT_PTR | VT_ARRAY))
+ n++, t = t->type.ref;
+ else
+ break;
+ }
+ for (i = 0; i < sizeof(default_debug) / sizeof(default_debug[0]); i++)
+ if (default_debug[i].type == type)
+ break;
+ if (i == sizeof(default_debug) / sizeof(default_debug[0]))
+#if 0
+ return;
+#else
+ /* XXX: Map Struct/Union/Enum/Bitfield to void/char */
+ i = n > 0 ? i - 1 : 1; /* 'void a;' is illegal so use char instead. */
+#endif
+ if (n > 0)
+ /* XXX: Optimize. Merge type info */
+ cstr_printf (result, "%d=", ++debug_next_type);
+ t = s;
+ for (;;) {
+ type = t->type.t & ~(VT_EXTERN | VT_STATIC | VT_CONSTANT |
VT_VOLATILE);
+ if ((type & VT_BTYPE) != VT_BYTE)
+ type &= ~VT_DEFSIGN;
+ if (type == VT_PTR)
+ cstr_cat (result, "*", -1);
+ else if (type == (VT_PTR | VT_ARRAY))
+ /* XXX: Optimize. Merge type info */
+ cstr_printf (result, "%d=ar1;0;%d;",
+ ++debug_next_type, t->type.ref->c - 1);
+ else
+ break;
+ t = t->type.ref;
+ }
+ cstr_printf (result, "%d", i + 1);
+}
+
+static void tcc_debug_stabs (const char *str, int type, unsigned long value)
+{
+ struct debug_sym *s;
+
+ debug_info->sym =
+ (struct debug_sym *)tcc_realloc (debug_info->sym,
+ sizeof(struct debug_sym) *
+ (debug_info->n_sym + 1));
+ s = debug_info->sym + debug_info->n_sym++;
+ s->type = type;
+ s->value = value;
+ s->str = tcc_strdup(str);
+}
+
+static void tcc_debug_stabn(int type, int value)
+{
+ if (!tcc_state->do_debug)
+ return;
+ if (type == N_LBRAC) {
+ struct debug_info *info =
+ (struct debug_info *) tcc_mallocz(sizeof (*info));
+
+ info->start = value;
+ info->parent = debug_info;
+ if (debug_info) {
+ if (debug_info->child) {
+ if (debug_info->child->last)
+ debug_info->child->last->next = info;
+ else
+ debug_info->child->next = info;
+ debug_info->child->last = info;
+ }
+ else
+ debug_info->child = info;
+ }
+ else
+ debug_info_root = info;
+ debug_info = info;
+ }
+ else {
+ debug_info->end = value;
+ debug_info = debug_info->parent;
+ }
+}
+
+static void tcc_debug_finish (struct debug_info *cur)
+{
+ while (cur) {
+ int i;
+ struct debug_info *next = cur->next;
+
+ for (i = 0; i < cur->n_sym; i++) {
+ put_stabs(tcc_state, cur->sym[i].str, cur->sym[i].type,
+ 0, 0, cur->sym[i].value);
+ tcc_free (cur->sym[i].str);
+ }
+ tcc_free (cur->sym);
+ put_stabn(tcc_state, N_LBRAC, 0, 0, cur->start);
+ tcc_debug_finish (cur->child);
+ put_stabn(tcc_state, N_RBRAC, 0, 0, cur->end);
+ tcc_free (cur);
+ cur = next;
+ }
+}
+
+static void tcc_add_debug_info(int param, Sym *s, Sym *e)
+{
+ if (!tcc_state->do_debug)
+ return;
+ for (; s != e; s = s->prev) {
+ if (!s->v || (s->r & VT_VALMASK) != VT_LOCAL)
+ continue;
+ cstr_reset (&debug_str);
+ cstr_printf (&debug_str, "%s:%s", get_tok_str(s->v, NULL), param ? "p"
: "");
+ tcc_get_debug_info(s, &debug_str);
+ tcc_debug_stabs(debug_str.data, param ? N_PSYM : N_LSYM, s->c);
+ }
+}
+
/* put end of translation unit info */
ST_FUNC void tcc_debug_end(TCCState *s1)
{
@@ -394,14 +578,14 @@ ST_FUNC void tcc_debug_line(TCCState *s1)
/* put function symbol */
ST_FUNC void tcc_debug_funcstart(TCCState *s1, Sym *sym)
{
- char buf[512];
BufferedFile *f;
if (!s1->do_debug || !(f = put_new_file(s1)))
return;
- /* XXX: we put here a dummy type */
- snprintf(buf, sizeof(buf), "%s:%c1",
- funcname, sym->type.t & VT_STATIC ? 'f' : 'F');
- put_stabs_r(s1, buf, N_FUN, 0, f->line_num, 0, cur_text_section, sym->c);
+ tcc_debug_stabn(N_LBRAC, ind - func_ind);
+ cstr_reset (&debug_str);
+ cstr_printf(&debug_str, "%s:%c", funcname, sym->type.t & VT_STATIC ? 'f' :
'F');
+ tcc_get_debug_info(sym->type.ref, &debug_str);
+ put_stabs_r(s1, debug_str.data, N_FUN, 0, f->line_num, 0,
cur_text_section, sym->c);
tcc_debug_line(s1);
}
@@ -410,6 +594,10 @@ ST_FUNC void tcc_debug_funcend(TCCState *s1, int size)
{
if (!s1->do_debug)
return;
+ tcc_debug_stabn(N_RBRAC, ind - func_ind);
+ tcc_debug_finish (debug_info_root);
+ debug_info_root = NULL;
+ cstr_free (&debug_str);
put_stabn(s1, N_FUN, 0, 0, size);
}
@@ -562,7 +750,6 @@ ST_FUNC void put_extern_sym2(Sym *sym, int sh_num,
#ifdef CONFIG_TCC_BCHECK
char buf[32];
#endif
-
if (!sym->c) {
name = get_tok_str(sym->v, NULL);
#ifdef CONFIG_TCC_BCHECK
@@ -637,6 +824,25 @@ ST_FUNC void put_extern_sym2(Sym *sym, int sh_num,
name = get_tok_str(sym->asm_label, NULL);
info = ELFW(ST_INFO)(sym_bind, sym_type);
sym->c = put_elf_sym(symtab_section, value, size, info, other, sh_num,
name);
+ if (tcc_state->do_debug && sym_type != STT_FUNC && sym->v <
SYM_FIRST_ANOM) {
+ CString str;
+
+ cstr_new (&str);
+ cstr_printf (&str, "%s:%c", get_tok_str(sym->v, NULL),
+ sym_bind == STB_GLOBAL ? 'G' : 'S');
+ tcc_get_debug_info(sym, &str);
+ if (sym_bind == STB_GLOBAL)
+ put_stabs(tcc_state, str.data, N_GSYM, 0, 0, 0);
+ else
+ put_stabs_r(tcc_state, str.data,
+ (t & VT_STATIC) && data_section->sh_num == sh_num
+ ? N_STSYM : N_LCSYM, 0, 0, 0,
+ data_section->sh_num == sh_num ? data_section :
+ bss_section->sh_num == sh_num ? bss_section :
+ common_section->sh_num == sh_num ? common_section :
+ text_section, sym->c);
+ cstr_free (&str);
+ }
} else {
esym = elfsym(sym);
esym->st_value = value;
@@ -1623,12 +1829,13 @@ static void add_local_bounds(Sym *s, Sym *e)
#endif
/* Wrapper around sym_pop, that potentially also registers local bounds. */
-static void pop_local_syms(Sym **ptop, Sym *b, int keep, int ellipsis)
+static void pop_local_syms(int param, Sym **ptop, Sym *b, int keep, int
ellipsis)
{
#ifdef CONFIG_TCC_BCHECK
if (!ellipsis && !keep && tcc_state->do_bounds_check)
add_local_bounds(*ptop, b);
#endif
+ tcc_add_debug_info (param, *ptop, b);
sym_pop(ptop, b, keep);
}
@@ -6326,6 +6533,7 @@ void new_scope(struct scope *o)
o->llstk = local_label_stack;
++local_scope;
+ tcc_debug_stabn(N_LBRAC, ind - func_ind);
}
void prev_scope(struct scope *o, int is_expr)
@@ -6347,7 +6555,9 @@ void prev_scope(struct scope *o, int is_expr)
tables, though. sym_pop will do that. */
/* pop locally defined symbols */
- pop_local_syms(&local_stack, o->lstk, is_expr, 0);
+ pop_local_syms(0, &local_stack, o->lstk, is_expr, 0);
+
+ tcc_debug_stabn(N_RBRAC, ind - func_ind);
cur_scope = o->prev;
--local_scope;
@@ -7573,7 +7783,7 @@ static void gen_function(Sym *sym)
gsym(rsym);
nocode_wanted = 0;
/* reset local stack */
- pop_local_syms(&local_stack, NULL, 0,
+ pop_local_syms(1, &local_stack, NULL, 0,
sym->type.ref->f.func_type == FUNC_ELLIPSIS);
gfunc_epilog();
cur_text_section->data_offset = ind;
_______________________________________________
Tinycc-devel mailing list
Tinycc-devel@nongnu.org
https://lists.nongnu.org/mailman/listinfo/tinycc-devel