[nasm:debug-macros] debug: collect macro information for the debug backend

nasm-bot for H. Peter Anvin (Intel) hpa at zytor.com
Thu Jul 9 17:51:05 PDT 2020


Commit-ID:  50184c26c760506744f5ccf699d0e1a8cd0cddbe
Gitweb:     http://repo.or.cz/w/nasm.git?a=commitdiff;h=50184c26c760506744f5ccf699d0e1a8cd0cddbe
Author:     H. Peter Anvin (Intel) <hpa at zytor.com>
AuthorDate: Wed, 8 Jul 2020 09:28:44 -0700
Committer:  H. Peter Anvin (Intel) <hpa at zytor.com>
CommitDate: Wed, 8 Jul 2020 09:28:44 -0700

debug: collect macro information for the debug backend

Collect macro call/nesting information for the benefit of the debug
back end. So far, the only backend for which this is provided is the
debug back end, to show what information is present.

Signed-off-by: H. Peter Anvin (Intel) <hpa at zytor.com>


---
 asm/assemble.c    |  26 ++++++-
 asm/preproc.c     | 218 +++++++++++++++++++++++++++++++++++++++++++++++-------
 include/dbginfo.h | 115 ++++++++++++++++++++++++++++
 include/nasm.h    |  11 ++-
 output/codeview.c |   1 +
 output/nulldbg.c  |   1 +
 output/outdbg.c   |  73 ++++++++++++++++--
 output/outelf.c   |   6 ++
 output/outieee.c  |   1 +
 output/outmacho.c |   2 +
 output/outobj.c   |   1 +
 11 files changed, 421 insertions(+), 34 deletions(-)

diff --git a/asm/assemble.c b/asm/assemble.c
index e5d5682c..1093f4dd 100644
--- a/asm/assemble.c
+++ b/asm/assemble.c
@@ -186,6 +186,7 @@
 #include "tables.h"
 #include "disp8.h"
 #include "listing.h"
+#include "dbginfo.h"
 
 enum match_result {
     /*
@@ -323,6 +324,24 @@ static void warn_overflow_out(int64_t data, int size, enum out_sign sign)
         warn_overflow(size);
 }
 
+/*
+ * Collect macro-related debug information, if applicable.
+ */
+static void debug_macro_out(const struct out_data *data)
+{
+    struct debug_macro_addr *addr;
+    uint64_t start = data->offset;
+    uint64_t end  = start + data->size;
+
+    addr = debug_macro_get_addr(data->segment);
+    while (addr) {
+        if (!addr->len)
+            addr->start = start;
+        addr->len = end - addr->start;
+        addr = addr->up;
+    }
+}
+
 /*
  * This routine wrappers the real output format's output routine,
  * in order to pass a copy of the data off to the listing file
@@ -405,10 +424,15 @@ static void out(struct out_data *data)
      * changed, and the amount by which lineno changed,
      * if it did. thus, these variables must be static
      */
-
     if (src_get(&lineno, &lnfname))
         dfmt->linenum(lnfname, lineno, data->segment);
 
+    /*
+     * Collect macro-related information for the debugger, if applicable
+     */
+    if (debug_current_macro)
+        debug_macro_out(data);
+
     if (asize > amax) {
         if (data->type == OUT_RELADDR || data->sign == OUT_SIGNED) {
             nasm_nonfatal("%u-bit signed relocation unsupported by output format %s",
diff --git a/asm/preproc.c b/asm/preproc.c
index 81c72042..87e03470 100644
--- a/asm/preproc.c
+++ b/asm/preproc.c
@@ -75,6 +75,7 @@
 #include "tokens.h"
 #include "tables.h"
 #include "listing.h"
+#include "dbginfo.h"
 
 /*
  * Preprocessor execution options that can be controlled by %pragma or
@@ -86,6 +87,10 @@ static struct pp_opts {
     bool sane_empty_expansion;
 } ppopt;
 
+static enum pp_debug_flags {
+    PDBG_MACROS = 1              /* Collect macro information */
+} ppdbg;
+
 typedef struct SMacro SMacro;
 typedef struct MMacro MMacro;
 typedef struct MMacroInvocation MMacroInvocation;
@@ -296,6 +301,10 @@ struct MMacro {
     int *paramlen;
     uint64_t unique;
     uint64_t condcnt;           /* number of if blocks... */
+    struct {                    /* Debug information */
+        struct debug_macro_def *def; /* Definition */
+        struct debug_macro_inv *inv; /* Current invocation (if any) */
+    } dbg;
 };
 
 
@@ -3820,10 +3829,11 @@ static int do_directive(Token *tline, Token **output)
             inc->lineinc = 1;
             inc->nolist = istk->nolist;
             inc->noline = istk->noline;
-            if (!inc->noline)
-                src_set(0, found_path ? found_path : p);
             istk = inc;
-            lfmt->uplevel(LIST_INCLUDE, 0);
+            if (!istk->noline)
+                src_set(0, found_path ? found_path : p);
+            if (!istk->nolist)
+                lfmt->uplevel(LIST_INCLUDE, 0);
         }
         break;
 
@@ -3847,12 +3857,15 @@ static int do_directive(Token *tline, Token **output)
             stdmacpos = pkg->macros;
             nasm_new(inc);
             inc->next = istk;
-            inc->nolist = istk->nolist + !list_option('b');
-            inc->noline = istk->noline;
+            if (!list_option('b')) {
+                inc->nolist++;
+                inc->noline++;
+            }
+            istk = inc;
+            if (!istk->nolist)
+                lfmt->uplevel(LIST_INCLUDE, 0);
             if (!inc->noline)
                 src_set(0, NULL);
-            istk = inc;
-            lfmt->uplevel(LIST_INCLUDE, 0);
         }
         break;
     }
@@ -6111,6 +6124,145 @@ static void list_mmacro_call(const MMacro *m)
     nasm_free(buf);
 }
 
+/*
+ * Collect information about macro invocations for the benefit of
+ * the debugger. During execution we create a reverse list; before
+ * calling the backend reverse it to definition/invocation order just
+ * to be nicer. [XXX: not implemented yet]
+ */
+struct debug_macro_inv *debug_current_macro;
+
+/* Get/create a addr structure for a seg:inv combo */
+static struct debug_macro_addr *
+debug_macro_get_addr_inv(int32_t seg, struct debug_macro_inv *inv)
+{
+    struct debug_macro_addr *addr;
+
+    if (likely(seg == inv->lastseg))
+        return inv->addr.last;
+
+    inv->lastseg = seg;
+    addr = (struct debug_macro_addr *)rb_search(inv->addr.tree, seg);
+    if (unlikely(!addr)) {
+        nasm_new(addr);
+        addr->tree.key = seg;
+        inv->addr.tree = rb_insert(inv->addr.tree, &addr->tree);
+        inv->naddr++;
+        if (inv->up)
+            addr->up = debug_macro_get_addr_inv(seg, inv->up);
+    }
+
+    return inv->addr.last = addr;
+}
+
+/* Get/create an addr structure for a seg in debug_current_macro */
+struct debug_macro_addr *debug_macro_get_addr(int32_t seg)
+{
+    return debug_macro_get_addr_inv(seg, debug_current_macro);
+}
+
+static struct debug_macro_info dmi;
+static struct debug_macro_inv_list *current_inv_list = &dmi.inv;
+
+static void debug_macro_start(MMacro *m, struct src_location where)
+{
+    struct debug_macro_def *def = m->dbg.def;
+    struct debug_macro_inv *inv;
+
+    nasm_assert(!m->dbg.inv);
+
+    /* First invocation? Need to create a def structure */
+    if (unlikely(!def)) {
+        nasm_new(def);
+        def->name = nasm_strdup(m->name);
+        def->where = m->where;
+
+        def->next = dmi.def.l;
+        dmi.def.l = def;
+        dmi.def.n++;
+
+        m->dbg.def = def;
+    }
+
+    nasm_new(inv);
+    inv->lastseg = NO_SEG;
+    inv->where = where;
+    inv->up = debug_current_macro;
+    inv->next = current_inv_list->l;
+    inv->def = def;
+    current_inv_list->l = inv;
+    current_inv_list->n++;
+    current_inv_list = &inv->down;
+
+    def->ninv++;
+    m->dbg.inv = inv;
+    debug_current_macro = inv;
+}
+
+static void debug_macro_end(MMacro *m)
+{
+    struct debug_macro_inv *inv = m->dbg.inv;
+
+    nasm_assert(inv == debug_current_macro);
+
+    m->dbg.inv = NULL;
+    inv = inv->up;
+
+    m = istk->mstk.mmac;
+    if (m) {
+        nasm_assert(inv == m->dbg.inv);
+        debug_current_macro = inv;
+        current_inv_list = &inv->down;
+    } else {
+        nasm_assert(!inv);
+        debug_current_macro = NULL;
+        current_inv_list = &dmi.inv;
+    }
+}
+
+static void free_debug_macro_addr_tree(struct rbtree *tree)
+{
+    struct rbtree *left, *right;
+    static_assert(offsetof(struct debug_macro_addr,tree) == 0);
+
+    if (!tree)
+        return;
+
+    left  = rb_left(tree);
+    right = rb_right(tree);
+
+    nasm_free(tree);
+
+    free_debug_macro_addr_tree(left);
+    free_debug_macro_addr_tree(right);
+}
+
+static void free_debug_macro_inv_list(struct debug_macro_inv *inv)
+{
+    struct debug_macro_inv *itmp;
+
+    if (!inv)
+        return;
+
+    list_for_each_safe(inv, itmp, inv) {
+        free_debug_macro_inv_list(inv->down.l);
+        free_debug_macro_addr_tree(inv->addr.tree);
+        nasm_free(inv);
+    }
+}
+
+static void free_debug_macro_info(void)
+{
+    struct debug_macro_def *def, *dtmp;
+
+    list_for_each_safe(def, dtmp, dmi.def.l)
+        nasm_free(def);
+
+    free_debug_macro_inv_list(dmi.inv.l);
+
+    nasm_zero(dmi);
+}
+
 /*
  * Expand the multi-line macro call made by the given line, if
  * there is one to be expanded. If there is, push the expansion on
@@ -6316,10 +6468,13 @@ static int expand_mmacro(Token * tline)
     istk->noline += !!(m->nolist & NL_LINE);
 
     if (!istk->nolist) {
-        lfmt->uplevel(LIST_MACRO, 0);
-
         if (list_option('m'))
             list_mmacro_call(m);
+
+        lfmt->uplevel(LIST_MACRO, 0);
+
+        if (ppdbg & PDBG_MACROS)
+            debug_macro_start(m, src_where());
     }
 
     if (!istk->noline)
@@ -6447,6 +6602,13 @@ pp_reset(const char *file, enum preproc_mode mode, struct strlist *dep_list)
     /* Reset options to default */
     nasm_zero(ppopt);
 
+    /* Disable all debugging info, except in the last pass */
+    ppdbg = 0;
+    if (pass_final()) {
+        if (dfmt->debug_macros)
+            ppdbg |= PDBG_MACROS;
+    }
+
     if (!use_loaded)
         use_loaded = nasm_malloc(use_package_count * sizeof(bool));
     memset(use_loaded, 0, use_package_count * sizeof(bool));
@@ -6472,9 +6634,10 @@ pp_reset(const char *file, enum preproc_mode mode, struct strlist *dep_list)
     inc->next = istk;
     src_set(0, NULL);
     inc->where = src_where();
-    inc->nolist = !list_option('b');
+    inc->nolist = inc->noline = !list_option('b');
     istk = inc;
-    lfmt->uplevel(LIST_INCLUDE, 0);
+    if (!istk->nolist)
+        lfmt->uplevel(LIST_INCLUDE, 0);
 
     pp_add_magic_stdmac();
 
@@ -6627,12 +6790,6 @@ static Token *pp_tokline(void)
                     }
                 }
 
-                if (fm->nolist & NL_LIST) {
-                    istk->nolist--;
-                } else if (!istk->nolist) {
-                    lfmt->downlevel(LIST_MACRO);
-                }
-
                 if (fm->nolist & NL_LINE) {
                     istk->noline--;
                 } else if (!istk->noline) {
@@ -6641,6 +6798,14 @@ static Token *pp_tokline(void)
                     src_update(l->where);
                 }
 
+                if (fm->nolist & NL_LIST) {
+                    istk->nolist--;
+                } else if (!istk->nolist) {
+                    lfmt->downlevel(LIST_MACRO);
+                    if ((ppdbg & PDBG_MACROS) && fm->name)
+                        debug_macro_end(fm);
+                }
+
                 istk->where = l->where;
 
                 /*
@@ -6688,7 +6853,6 @@ static Token *pp_tokline(void)
                  * The current file has ended; work down the istk
                  */
                 Include *i = istk;
-                Include *is;
 
                 if (i->fp)
                     fclose(i->fp);
@@ -6697,14 +6861,13 @@ static Token *pp_tokline(void)
                     nasm_fatal("expected `%%endif' before end of file");
                 }
 
-                list_for_each(is, i->next) {
-                    if (is->fp) {
-                        lfmt->downlevel(LIST_INCLUDE);
-                        src_update(is->where);
-                        break;
-                    }
-                }
                 istk = i->next;
+
+                if (!i->nolist)
+                    lfmt->downlevel(LIST_INCLUDE);
+                if (!i->noline && istk)
+                    src_update(istk->where);
+
                 nasm_free(i);
                 return &tok_pop;
             }
@@ -6845,6 +7008,11 @@ static void pp_cleanup_pass(void)
     while (cstk)
         ctx_pop();
     src_set_fname(NULL);
+
+    if (ppdbg & PDBG_MACROS) {
+        dfmt->debug_macros(&dmi);
+        free_debug_macro_info();
+    }
 }
 
 static void pp_cleanup_session(void)
diff --git a/include/dbginfo.h b/include/dbginfo.h
new file mode 100644
index 00000000..8584eda3
--- /dev/null
+++ b/include/dbginfo.h
@@ -0,0 +1,115 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2020 The NASM Authors - All Rights Reserved
+ *   See the file AUTHORS included with the NASM distribution for
+ *   the specific copyright holders.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following
+ *   conditions are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the following
+ *     disclaimer in the documentation and/or other materials provided
+ *     with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * dbginfo.h - debugging info structures
+ */
+
+#ifndef NASM_DBGINFO_H
+#define NASM_DBGINFO_H
+
+#include "compiler.h"
+#include "srcfile.h"
+#include "rbtree.h"
+
+struct debug_macro_def;         /* Definition */
+struct debug_macro_inv;         /* Invocation */
+struct debug_macro_addr;        /* Address range */
+
+/*
+ * Definitions structure, one for each non-.nolist macro invoked
+ * anywhere in the program; unique for each macro, even if a macro is
+ * redefined and/or overloaded.
+ */
+struct debug_macro_def {
+    struct debug_macro_def *next; /* List of definitions */
+    const char *name;            /* Macro name */
+    struct src_location where;   /* Start of definition */
+    size_t ninv;                 /* Call count */
+};
+
+/*
+ * Invocation structure. One for each invocation of a non-.nolist macro.
+ */
+struct debug_macro_inv_list {
+    struct debug_macro_inv *l;
+    size_t n;
+};
+
+struct debug_macro_inv {
+    struct debug_macro_inv *next; /* List of same-level invocations */
+    struct debug_macro_inv_list down;
+    struct debug_macro_inv *up;   /* Parent invocation */
+    struct debug_macro_def *def;  /* Macro definition */
+    struct src_location where;    /* Start of invocation */
+    struct {                      /* Address range pointers */
+        struct rbtree *tree;           /* rbtree of address ranges */
+        struct debug_macro_addr *last; /* Quick lookup for latest section */
+    } addr;
+    uint32_t naddr;             /* Number of address ranges */
+    int32_t  lastseg;           /* lastaddr segment number  */
+};
+
+/*
+ * Address range structure. An rbtree containing one address range for each
+ * section which this particular macro has generated code/data/space into.
+ */
+struct debug_macro_addr {
+    struct rbtree tree;          /* rbtree; key = index, must be first */
+    struct debug_macro_addr *up; /* same section in parent invocation */
+    uint64_t start;              /* starting offset */
+    uint64_t len;                /* length of range */
+};
+
+/*
+ * Complete information structure */
+struct debug_macro_info {
+    struct debug_macro_inv_list inv;
+    struct debug_macro_def_list {
+        struct debug_macro_def *l;
+        size_t n;
+    } def;
+};
+
+static inline int32_t debug_macro_seg(const struct debug_macro_addr *dma)
+{
+    return dma->tree.key;
+}
+
+/* Get/create a addr structure for the macro we are emitting for */
+struct debug_macro_addr *debug_macro_get_addr(int32_t seg);
+
+/* The macro we are currently emitting for, if any */
+extern struct debug_macro_inv *debug_current_macro;
+
+#endif /* NASM_DBGINFO_H */
diff --git a/include/nasm.h b/include/nasm.h
index efeb6190..3c9ce962 100644
--- a/include/nasm.h
+++ b/include/nasm.h
@@ -1,6 +1,6 @@
 /* ----------------------------------------------------------------------- *
  *
- *   Copyright 1996-2018 The NASM Authors - All Rights Reserved
+ *   Copyright 1996-2020 The NASM Authors - All Rights Reserved
  *   See the file AUTHORS included with the NASM distribution for
  *   the specific copyright holders.
  *
@@ -1004,6 +1004,7 @@ extern FILE *ofile;
  * interfaces to the functions therein.
  * ------------------------------------------------------------
  */
+struct debug_macro_info;
 
 struct dfmt {
     /*
@@ -1036,6 +1037,14 @@ struct dfmt {
 
     void (*debug_deflabel)(char *name, int32_t segment, int64_t offset,
                            int is_global, char *special);
+
+    /*
+     * debug_macros - called once at the end with a definition for each
+     * non-.nolist macro that has been invoked at least once in the program,
+     * and the corresponding address ranges. See dbginfo.h.
+     */
+    void (*debug_macros)(const struct debug_macro_info *);
+
     /*
      * debug_directive - called whenever a DEBUG directive other than 'LINE'
      * is encountered. 'directive' contains the first parameter to the
diff --git a/output/codeview.c b/output/codeview.c
index be3fd27a..f424bec6 100644
--- a/output/codeview.c
+++ b/output/codeview.c
@@ -64,6 +64,7 @@ const struct dfmt df_cv8 = {
     cv8_init,                   /* .init */
     cv8_linenum,                /* .linenum */
     cv8_deflabel,               /* .debug_deflabel */
+    NULL,                       /* .debug_macros */
     null_debug_directive,       /* .debug_directive */
     cv8_typevalue,              /* .debug_typevalue */
     cv8_output,                 /* .debug_output */
diff --git a/output/nulldbg.c b/output/nulldbg.c
index 69e89a66..7b422357 100644
--- a/output/nulldbg.c
+++ b/output/nulldbg.c
@@ -83,6 +83,7 @@ const struct dfmt null_debug_form = {
     null_debug_init,
     null_debug_linenum,
     null_debug_deflabel,
+    NULL,                       /* .debug_macros */
     null_debug_directive,
     null_debug_typevalue,
     null_debug_output,
diff --git a/output/outdbg.c b/output/outdbg.c
index 2304992f..a823fdff 100644
--- a/output/outdbg.c
+++ b/output/outdbg.c
@@ -1,6 +1,6 @@
 /* ----------------------------------------------------------------------- *
  *
- *   Copyright 1996-2018 The NASM Authors - All Rights Reserved
+ *   Copyright 1996-2020 The NASM Authors - All Rights Reserved
  *   See the file AUTHORS included with the NASM distribution for
  *   the specific copyright holders.
  *
@@ -46,6 +46,7 @@
 #include "outform.h"
 #include "outlib.h"
 #include "insns.h"
+#include "dbginfo.h"
 
 #ifdef OF_DBG
 
@@ -137,7 +138,7 @@ static int32_t dbg_herelabel(const char *name, enum label_type type,
                              bool *copyoffset)
 {
     int32_t newseg = oldseg;
-    
+
     if (subsections_via_symbols && type != LBL_LOCAL) {
         newseg = *subsection;
         if (newseg == NO_SEG) {
@@ -397,41 +398,98 @@ static const char * const types[] = {
 };
 static void dbgdbg_init(void)
 {
-    fprintf(ofile, "   With debug info\n");
+    fprintf(ofile, "dbg init: debug information enabled\n");
 }
 static void dbgdbg_cleanup(void)
 {
+    fprintf(ofile, "dbg cleanup: called\n");
 }
 
 static void dbgdbg_linnum(const char *lnfname, int32_t lineno, int32_t segto)
 {
-    fprintf(ofile, "dbglinenum %s(%"PRId32") segment %"PRIx32"\n",
+    fprintf(ofile, "dbg linenum: %s(%"PRId32") segment %"PRIx32"\n",
 	    lnfname, lineno, segto);
 }
 static void dbgdbg_deflabel(char *name, int32_t segment,
                             int64_t offset, int is_global, char *special)
 {
-    fprintf(ofile, "dbglabel %s := %08"PRIx32":%016"PRIx64" %s (%d)%s%s\n",
+    fprintf(ofile, "dbg deflabel: %s = %08"PRIx32":%016"PRIx64" %s (%d)%s%s\n",
             name,
             segment, offset,
             is_global == 2 ? "common" : is_global ? "global" : "local",
             is_global, special ? ": " : "", special);
 }
+
 static void dbgdbg_define(const char *type, const char *params)
 {
-    fprintf(ofile, "dbgdirective [%s] value [%s]\n", type, params);
+    fprintf(ofile, "dbg directive: [%s] value [%s]\n", type, params);
 }
 static void dbgdbg_output(int output_type, void *param)
 {
     (void)output_type;
     (void)param;
+    fprintf(ofile, "dbg output: called\n");
 }
 static void dbgdbg_typevalue(int32_t type)
 {
-    fprintf(ofile, "new type: %s(%"PRIX32")\n",
+    fprintf(ofile, "dbg typevalue: %s(%"PRIX32")\n",
             types[TYM_TYPE(type) >> 3], TYM_ELEMENTS(type));
 }
 
+static void
+write_macro_inv_list(const struct debug_macro_inv *inv, int level)
+{
+    int indent = (level+1) << 1;
+
+    while (inv) {
+        const struct rbtree *rb;
+
+        fprintf(ofile, "%*smacro: %s, invoked at %s:%"PRId32
+                ", %"PRIu32" ranges\n",
+                indent, "", inv->def->name, inv->where.filename,
+                inv->where.lineno, inv->naddr);
+
+        for (rb = rb_first(inv->addr.tree); rb; rb = rb_next(rb)) {
+            const struct debug_macro_addr *addr =
+                (const struct debug_macro_addr *)rb;
+            if (!addr->len) {
+                fprintf(ofile, "%*s%08"PRIx32": empty\n",
+                        indent+2, "", debug_macro_seg(addr));
+            } else {
+                fprintf(ofile,
+                        "%*s%08"PRIx32":[%016"PRIx64" ... %016"PRIx64"] "
+                        "len %"PRIu64"\n",
+                        indent+2, "",
+                        debug_macro_seg(addr), addr->start,
+                        addr->start + addr->len - 1, addr->len);
+            }
+        }
+
+        write_macro_inv_list(inv->down.l, level+1);
+        inv = inv->next;
+    }
+}
+
+static void dbgdbg_debug_macros(const struct debug_macro_info *dmi)
+{
+    const struct debug_macro_def *def;
+
+    fprintf(ofile, "dbg macros: %llu macros defined\n",
+            (unsigned long long)dmi->def.n);
+
+    fprintf(ofile, "  macro definitions:\n");
+    list_for_each(def, dmi->def.l) {
+        fprintf(ofile, "    macro: %s, count %llu, defined at %s:%"PRId32"\n",
+                def->name, (unsigned long long)def->ninv,
+                def->where.filename, def->where.lineno);
+    }
+
+    fprintf(ofile, "  macro invocations:\n");
+    write_macro_inv_list(dmi->inv.l, 1);
+
+    fprintf(ofile, "  end macro debug information\n");
+}
+
 static const struct pragma_facility dbgdbg_pragma_list[] = {
     { "dbgdbg", dbg_pragma },
     { NULL, dbg_pragma }        /* Won't trigger, "debug" is a reserved ns */
@@ -443,6 +501,7 @@ static const struct dfmt debug_debug_form = {
     dbgdbg_init,
     dbgdbg_linnum,
     dbgdbg_deflabel,
+    dbgdbg_debug_macros,
     dbgdbg_define,
     dbgdbg_typevalue,
     dbgdbg_output,
diff --git a/output/outelf.c b/output/outelf.c
index 61af0208..c80e9b99 100644
--- a/output/outelf.c
+++ b/output/outelf.c
@@ -2435,6 +2435,7 @@ static const struct dfmt elf32_df_dwarf = {
     dwarf32_init,
     dwarf_linenum,
     null_debug_deflabel,
+    NULL,                       /* .debug_macros */
     null_debug_directive,
     debug_typevalue,
     dwarf_output,
@@ -2448,6 +2449,7 @@ static const struct dfmt elf32_df_stabs = {
     null_debug_init,
     stabs_linenum,
     null_debug_deflabel,
+    NULL,                       /* .debug_macros */
     null_debug_directive,
     debug_typevalue,
     stabs_output,
@@ -2487,6 +2489,7 @@ static const struct dfmt elf64_df_dwarf = {
     dwarf64_init,
     dwarf_linenum,
     null_debug_deflabel,
+    NULL,                       /* .debug_macros */
     null_debug_directive,
     debug_typevalue,
     dwarf_output,
@@ -2500,6 +2503,7 @@ static const struct dfmt elf64_df_stabs = {
     null_debug_init,
     stabs_linenum,
     null_debug_deflabel,
+    NULL,                       /* .debug_macros */
     null_debug_directive,
     debug_typevalue,
     stabs_output,
@@ -2539,6 +2543,7 @@ static const struct dfmt elfx32_df_dwarf = {
     dwarfx32_init,
     dwarf_linenum,
     null_debug_deflabel,
+    NULL,                       /* .debug_macros */
     null_debug_directive,
     debug_typevalue,
     dwarf_output,
@@ -2552,6 +2557,7 @@ static const struct dfmt elfx32_df_stabs = {
     null_debug_init,
     stabs_linenum,
     null_debug_deflabel,
+    NULL,                       /* .debug_macros */
     null_debug_directive,
     debug_typevalue,
     stabs_output,
diff --git a/output/outieee.c b/output/outieee.c
index 4cc0f0f5..f474b8e5 100644
--- a/output/outieee.c
+++ b/output/outieee.c
@@ -1464,6 +1464,7 @@ static const struct dfmt ladsoft_debug_form = {
     dbgls_init,
     dbgls_linnum,
     dbgls_deflabel,
+    NULL,                       /* .debug_macros */
     null_debug_directive,
     dbgls_typevalue,
     dbgls_output,
diff --git a/output/outmacho.c b/output/outmacho.c
index 08147883..e3dbb850 100644
--- a/output/outmacho.c
+++ b/output/outmacho.c
@@ -2289,6 +2289,7 @@ static const struct dfmt macho32_df_dwarf = {
     macho_dbg_init,
     macho_dbg_linenum,
     null_debug_deflabel,
+    NULL,                       /* .debug_macros */
     null_debug_directive,
     null_debug_typevalue,
     macho_dbg_output,
@@ -2356,6 +2357,7 @@ static const struct dfmt macho64_df_dwarf = {
     macho_dbg_init,
     macho_dbg_linenum,
     null_debug_deflabel,
+    NULL,                       /* .debug_macros */
     null_debug_directive,
     null_debug_typevalue,
     macho_dbg_output,
diff --git a/output/outobj.c b/output/outobj.c
index 0d4d3110..09693207 100644
--- a/output/outobj.c
+++ b/output/outobj.c
@@ -2650,6 +2650,7 @@ static const struct dfmt borland_debug_form = {
     dbgbi_init,
     dbgbi_linnum,
     dbgbi_deflabel,
+    NULL,                       /* .debug_macros */
     null_debug_directive,
     dbgbi_typevalue,
     dbgbi_output,


More information about the Nasm-commits mailing list