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

Reply via email to