From 604e3ee43fcd0797580f3f804e414bee03b28aaf Mon Sep 17 00:00:00 2001 From: James Jones Date: Mon, 18 Jul 2022 00:35:28 -0700 Subject: [PATCH 2/2] Support -g debug info generation -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. --- 6502.c | 2 + docs/rmac.rst | 14 +++++++ op.c | 5 +++ procln.c | 3 ++ riscasm.c | 1 + rmac.c | 48 ++++++++++++++++------ rmac.h | 2 + symbol.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++-- symbol.h | 6 ++- 9 files changed, 175 insertions(+), 18 deletions(-) diff --git a/6502.c b/6502.c index 89029c1..c809a46 100644 --- 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 diff --git a/docs/rmac.rst b/docs/rmac.rst index 78e2d34..36dc5e0 100644 --- a/docs/rmac.rst +++ b/docs/rmac.rst @@ -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 9a4cc78..53fca21 100644 --- 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: diff --git a/procln.c b/procln.c index 52513e0..6d0dead 100644 --- 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; } diff --git a/riscasm.c b/riscasm.c index c3bd88f..7cda43a 100644 --- 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 5946105..841b01f 100644 --- 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,36 @@ 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) + { + // Validate option compatibility + if (dsym_flag && (obj_format != BSD)) + { + printf("-g: debug information only supported with BSD object file format\n"); + dsym_flag = 0; + errcnt++; + } + + // Record first filename. + firstfname = fname; + GenMainFileSym(dbgname); + } + + include(fd, dbgname); + Assemble(); +} + extern int reg68base[53]; extern int reg68tab[222]; extern int reg68check[222]; @@ -326,6 +358,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 +465,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 +640,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 +675,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 +686,7 @@ int Process(int argc, char ** argv) continue; } - include(fd, fnbuf); - Assemble(); + ProcessFile(fd, fnbuf); } } diff --git a/rmac.h b/rmac.h index 39f908e..5f23090 100644 --- 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; diff --git a/symbol.c b/symbol.c index 3b6e906..9288626 100644 --- 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)); @@ -564,12 +564,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); @@ -579,3 +579,107 @@ 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 (!dsym_flag) + return; + + 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 (!dsym_flag) + return; + + 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; +} diff --git a/symbol.h b/symbol.h index c10d71b..4554309 100644 --- 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,9 @@ 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); #endif // __SYMBOL_H__ -- 2.34.1