]> Shamusworld >> Repos - rmac/commitdiff
Support -g debug info generation
authorJames Jones <atari@theinnocuous.com>
Mon, 18 Jul 2022 07:35:28 +0000 (00:35 -0700)
committerShamus Hammons <jlhamm@acm.org>
Tue, 16 Aug 2022 02:08:10 +0000 (21:08 -0500)
-Add GenLineNoSym(), which will generate debug
 symbols for file names and line numbers when
 debug info generation is requested.

-Replace code that warns -g is not supported with
 code to set a flag.

-Complain if -g is specified for non-BSD output
 formats, as only stabs-in-symbol-table/a.out
 format debug information is supported currently.

-Document -g flag in usage information function.

-Document -g flag in manual.

v2:
-Only call debug symbol generation functions when
 dbg_sym != 0

6502.c
docs/rmac.rst
op.c
procln.c
riscasm.c
rmac.c
rmac.h
symbol.c
symbol.h

diff --git a/6502.c b/6502.c
index 89029c1488ed2b328926aa84fd6e345563ddec61..db6c638a621947c093f20098d4e77f85b82d0e36 100644 (file)
--- a/6502.c
+++ b/6502.c
@@ -423,6 +423,8 @@ badmode:
        DEBUG printf("inf[op][amode]=%d\n", (int)inf[op][amode]);
 #endif
 
+       GENLINENOSYM();
+
        switch (inf[op][amode])
        {
                case A65_IMPL:          // Just leave the instruction
index 78e2d34cb8fae27ae7f615745a65084666415479..36dc5e0ade2a63e047efd01898483c644560dfe0 100644 (file)
@@ -125,6 +125,7 @@ Switch               Description
 -fe                  ELF output object file format.
 -fr                  Absolute address. Source code is required to have one .org statement.
 -fx                  Atari 800 com/exe/xex output object file format.
+-g                   Generate source level debug info. Requires BSD COFF object file format.
 -i\ *path*           Set include-file directory search path.
 -l\ *[file[prn]]*    Construct and direct assembly listing to the specified file.
 -l\ *\*[filename]*   Create an output listing file without pagination.
@@ -235,6 +236,19 @@ the table.
  file is created. Beware! If an assembly produces no errors, any error file from
  a previous assembly is not removed.
 
+**-g**
+ The **-g** switch causes RMAC to generate source-level debug symbols using the
+ stabs format. When linked with a compatible linker such as RLN, these symbols
+ can be used by source-level debuggers such as rdbjag, wdb, or gdb to step
+ through assembly code line-by-line with all the additional context of labels,
+ macros, constants, register equates, etc. available in the original assembly
+ listings rather than relying on the simple disassembly or raw machine code
+ available when stepping through instruction-by-instruction. This option only
+ works with the BSD COFF object file format, as the others do not use the
+ a.out-style symbol tables required by stabs, and RMAC does not currently
+ support placing stabs debug symbols in their own dedicated section in ELF
+ format object files.
+
 **-i**
  The **-i** switch allows automatic directory searching for include files. A list of
  semi-colon seperated directory search paths may be mentioned immediately
diff --git a/op.c b/op.c
index 9a4cc784175dd599d4696d815a39590cc95b06db..6a7d51d6c45322bb213ff75769b2e6e53a0bbde1 100644 (file)
--- a/op.c
+++ b/op.c
@@ -46,6 +46,11 @@ int GenerateOPCode(int state)
        if (!robjproc)
                return error("opcode only valid in OP mode");
 
+       // It's OK to call this before validating state. If the state is invalid, an
+       // error will be generated and no object file will be produced, so it
+       // doesn't matter if the line number symbols are a little off.
+       GENLINENOSYM();
+
        switch (state)
        {
        case MO_BITMAP:
index 52513e0be04f7d42bbc4c7dc77c5f35b2dbbabb8..463ed1db9d461dbc928c3fc4653e19b67dcb8f7a 100644 (file)
--- a/procln.c
+++ b/procln.c
@@ -739,6 +739,7 @@ When checking to see if it's already been equated, issue a warning.
                        while ((dsp_am0 & md->mn0) == 0 || (dsp_am1 & md->mn1) == 0)
                                md = &dsp56k_machtab[md->mncont];
 
+                       GENLINENOSYM();
                        (*md->mnfunc)(md->mninst | (parcode << 8));
                        goto loop;
                }
@@ -784,6 +785,7 @@ When checking to see if it's already been equated, issue a warning.
        // Call special-mode handler
        if (m->mnattr & CGSPECIAL)
        {
+               GENLINENOSYM();
                (*m->mnfunc)(m->mninst, siz);
                goto loop;
        }
@@ -818,6 +820,7 @@ When checking to see if it's already been equated, issue a warning.
 
        DEBUG { printf("    68K: mninst=$%X, siz=$%X, mnattr=$%X, amsk0=$%X, mn0=$%X, amsk1=$%X, mn1=$%X\n", m->mninst, siz, m->mnattr, amsk0, m->mn0, amsk1, m->mn1); }
 
+       GENLINENOSYM();
        (*m->mnfunc)(m->mninst, siz);
        goto loop;
 }
index c3bd88f19f1fd67408718a8579b8fd6c8c3ad696..3399b81bd061f3afd0fddc6cbd7f625eb1ce9ba0 100644 (file)
--- a/riscasm.c
+++ b/riscasm.c
@@ -190,6 +190,7 @@ static void DepositRISCInstructionWord(uint16_t opcode, int reg1, int reg2)
        }
 
        int value = ((opcode & 0x3F) << 10) + ((reg1 & 0x1F) << 5) + (reg2 & 0x1F);
+       GENLINENOSYM();
        D_word(value);
 }
 
diff --git a/rmac.c b/rmac.c
index 5946105b03b0b68989ec8a19a2979a76aa6071db..f88f849a77963ed5ad5b2842dd83b7d1eb2ee2a9 100644 (file)
--- a/rmac.c
+++ b/rmac.c
@@ -31,6 +31,7 @@ int verb_flag;                                        // Be verbose about what's going on
 int m6502;                                             // 1, assembling 6502 code
 int glob_flag;                                 // Assume undefined symbols are global
 int lsym_flag;                                 // Include local symbols in object file (ALWAYS true)
+int dsym_flag;                                 // Gen debug syms (Requires obj_format = BSD)
 int optim_warn_flag;                   // Warn about possible short branches
 int prg_flag;                                  // !=0, produce .PRG executable (2=symbols)
 int prg_extend;                                        // !=0, output extended .PRG symbols
@@ -167,6 +168,7 @@ void DisplayHelp(void)
                "                    l: LOD (use this for DSP56001 only)\n"
                "                    x: com/exe/xex (Atari 800)\n"
                "                    r: absolute address\n"
+               "  -g                Output source level debug information (BSD object only)\n"
                "  -i[path]          Directory to search for include files\n"
                "  -l[filename]      Create an output listing file\n"
                "  -l*[filename]     Create an output listing file without pagination\n"
@@ -290,6 +292,42 @@ int ParseOptimization(char * optstring)
        return OK;
 }
 
+static void ProcessFile(int fd, char *fname)
+{
+       char *dbgname = fname;
+
+       if (NULL == fname)
+       {
+               fname = defname; // Kludge first filename
+               dbgname = "(stdin)";
+       }
+
+       // First file operations:
+       if (firstfname == NULL)
+       {
+               // Record first filename.
+               firstfname = fname;
+
+               // Validate option compatibility
+               if (dsym_flag)
+               {
+                       if (obj_format != BSD)
+                       {
+                               printf("-g: debug information only supported with BSD object file format\n");
+                               dsym_flag = 0;
+                               errcnt++;
+                       }
+                       else
+                       {
+                               GenMainFileSym(dbgname);
+                       }
+               }
+       }
+
+       include(fd, dbgname);
+       Assemble();
+}
+
 extern int reg68base[53];
 extern int reg68tab[222];
 extern int reg68check[222];
@@ -326,6 +364,7 @@ int Process(int argc, char ** argv)
        rdsp = 0;                                               // Initialize DSP assembly flag
        robjproc = 0;                                   // Initialize OP assembly flag
        lsym_flag = 1;                                  // Include local symbols in object file
+       dsym_flag = 0;                                  // No debug sym generation by default
        orgactive = 0;                                  // Not in RISC org section
        orgwarning = 0;                                 // No ORG warning issued
        segpadsize = 2;                                 // Initialize segment padding size
@@ -432,7 +471,7 @@ int Process(int argc, char ** argv)
                                break;
                        case 'g':                               // Debugging flag
                        case 'G':
-                               printf("Debugging flag (-g) not yet implemented\n");
+                               dsym_flag = 1;
                                break;
                        case 'i':                               // Set directory search path
                        case 'I':
@@ -607,11 +646,7 @@ int Process(int argc, char ** argv)
 
                                break;
                        case EOS:                               // Input is stdin
-                               if (firstfname == NULL) // Kludge first filename
-                                       firstfname = defname;
-
-                               include(0, "(stdin)");
-                               Assemble();
+                               ProcessFile(0, NULL);
                                break;
                        case 'h':                               // Display command line usage
                        case 'H':
@@ -646,10 +681,6 @@ int Process(int argc, char ** argv)
                }
                else
                {
-                       // Record first filename.
-                       if (firstfname == NULL)
-                               firstfname = argv[argno];
-
                        strcpy(fnbuf, argv[argno]);
                        fext(fnbuf, ".s", 0);
                        fd = open(fnbuf, 0);
@@ -661,8 +692,7 @@ int Process(int argc, char ** argv)
                                continue;
                        }
 
-                       include(fd, fnbuf);
-                       Assemble();
+                       ProcessFile(fd, fnbuf);
                }
        }
 
diff --git a/rmac.h b/rmac.h
index 39f908e0710c05232870140f7c2748c3e2b172fc..5f230909af12860ee90cc3564c634ea737847c71 100644 (file)
--- a/rmac.h
+++ b/rmac.h
@@ -28,6 +28,7 @@
        #define _OPEN_INC       _O_RDONLY|_O_BINARY
        #define _PERM_MODE      _S_IREAD|_S_IWRITE
     #define PATH_SEPS       ";"
+    #define realpath(_fn, _abs) _fullpath((_abs), (_fn), _MAX_PATH)
 
        #ifdef _MSC_VER
                #if _MSC_VER > 1000
@@ -302,6 +303,7 @@ extern int m6502;
 extern int list_flag;
 extern int glob_flag;
 extern int lsym_flag;
+extern int dsym_flag;
 extern int optim_warn_flag;
 extern int obj_format;
 extern int legacy_flag;
index 490d4f077fb388ae5c1508fb4454a505846b7f72..c9c34a4f6c729f34bedb94cc9ecf8204befe2a19 100644 (file)
--- a/symbol.c
+++ b/symbol.c
@@ -58,7 +58,7 @@ void InitSymbolTable(void)
 //
 // Hash the ASCII name and enviroment number
 //
-int HashSymbol(uint8_t * name, int envno)
+int HashSymbol(const uint8_t * name, int envno)
 {
        int sum = envno, k = 0;
 
@@ -76,7 +76,7 @@ int HashSymbol(uint8_t * name, int envno)
 //
 // Make a new symbol of type 'type' in enviroment 'envno'
 //
-SYM * NewSymbol(uint8_t * name, int type, int envno)
+SYM * NewSymbol(const uint8_t * name, int type, int envno)
 {
        // Allocate the symbol
        SYM * symbol = malloc(sizeof(SYM));
@@ -565,12 +565,12 @@ int symtable(void)
        return 0;
 }
 
-SYM * NewDebugSymbol(uint8_t * str, uint8_t type, uint8_t other, uint16_t desc)
+SYM * NewDebugSymbol(const uint8_t * str, uint8_t type, uint8_t other, uint16_t desc)
 {
        SYM * symbol = NewSymbol(str, DBGSYM, 0);
 
        if (NULL == symbol)
-               return NULL;
+               fatal("Could not allocate space for debug symbol");
 
        AddToSymbolDeclarationList(symbol);
 
@@ -580,3 +580,101 @@ SYM * NewDebugSymbol(uint8_t * str, uint8_t type, uint8_t other, uint16_t desc)
 
        return symbol;
 }
+
+char *FilePath(const char * fname)
+{
+       char buf1[256];
+       char * fpath;
+       int i, j;
+
+       if ((fpath = realpath(fname, NULL)) != NULL)
+               return fpath;
+
+       for(i=0; nthpath("RMACPATH", i, buf1)!=0; i++)
+       {
+               j = strlen(buf1);
+
+               // Append path char if necessary
+               if (j > 0 && buf1[j - 1] != SLASHCHAR)
+                       strcat(buf1, SLASHSTRING);
+
+               strcat(buf1, fname);
+
+               if ((fpath = realpath(buf1, NULL)) != NULL)
+                       return fpath;
+       }
+
+       return NULL;
+}
+
+static void GenFileSym(const char * fname, uint8_t type, uint32_t addr, uint32_t sattr)
+{
+       char *fpath;
+
+       if (!(fpath = FilePath(fname)))
+       {
+               // Don't treat this as an error. Any file rmac can read is valid enough.
+               // Just use the relative filename in place of an absolute path for the
+               // debug information.
+               fpath = strdup(fname);
+
+               if (!fpath)
+                       fatal("Could not allocate memory for fake path name");
+       }
+
+       SYM * symbol = NewDebugSymbol(fpath, type, 0, 0);
+
+       free(fpath);
+
+       symbol->svalue = addr;
+       symbol->sattr |= sattr;
+}
+
+void GenMainFileSym(const char * fname)
+{
+       GenFileSym(fname, 0x64 /* N_SO */, 0, DEFINED | TEXT);
+}
+
+void GenLineNoSym(void)
+{
+       uint32_t addr;
+       uint32_t sattr;
+       uint8_t type;
+       SYM * symbol;
+
+       static uint16_t prevlineno = -1;
+       static uint32_t prevaddr = -1;
+       static uint16_t prevfileno = 0;
+
+       if (orgactive)
+       {
+               addr = orgaddr;
+               sattr = ABS | DEFINED | EQUATED;
+               // 0x4c is N_FLINE, function start/body/end line number, repurposed by
+               // MADMAC/ALN for ABS line numbers.
+               type = 0x4c;
+       }
+       else
+       {
+               addr = pcloc;
+               sattr = DEFINED | cursect;
+               type = 0x44; // N_SLINE, text section line number
+       }
+
+       if ((addr == prevaddr) || ((curlineno == prevlineno) && (prevfileno == cfileno)))
+               return;
+
+       prevaddr = addr;
+       prevlineno = curlineno;
+
+       if (prevfileno != cfileno)
+               GenFileSym(curfname, 0x84 /* N_SOL */, addr, sattr);
+
+       prevfileno = cfileno;
+
+       /* MADMAC counts lines starting at 0. Offset curlineno accordingly */
+       symbol = NewDebugSymbol(NULL, type, 0, curlineno - 1);
+
+       symbol->svalue = addr;
+       symbol->sattr |= sattr;
+}
index c10d71b189f080c64c14541f66806959566510b7..4a84345aaaa8041fd2e497203da35903dccc8d7c 100644 (file)
--- a/symbol.h
+++ b/symbol.h
@@ -49,7 +49,7 @@ extern uint32_t firstglobal;// Index of the fist global symbol in an ELF object.
 // Exported functions
 SYM * lookup(uint8_t *, int, int);
 void InitSymbolTable(void);
-SYM * NewSymbol(uint8_t *, int, int);
+SYM * NewSymbol(const uint8_t *, int, int);
 void AddToSymbolDeclarationList(SYM *);
 void ForceUndefinedSymbolsGlobal(void);
 int symtable(void);
@@ -57,7 +57,12 @@ uint32_t AssignSymbolNos(uint8_t *, uint8_t *(*)());
 uint32_t AssignSymbolNosELF(uint8_t *, uint8_t *(*)());
 void DumpLODSymbols(void);
 uint8_t * GetSymbolNameByUID(uint32_t);
-SYM * NewDebugSymbol(uint8_t *, uint8_t, uint8_t, uint16_t);
+SYM * NewDebugSymbol(const uint8_t *, uint8_t, uint8_t, uint16_t);
+void GenMainFileSym(const char *);
+void GenLineNoSym(void);
+
+// Helper to avoid unnecessary branches:
+#define GENLINENOSYM() if (dsym_flag) GenLineNoSym()
 
 #endif // __SYMBOL_H__