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.

v2:
-Only call debug symbol generation functions when
 dbg_sym != 0
This commit is contained in:
James Jones 2022-07-18 00:35:28 -07:00 committed by Shamus Hammons
parent e8f9d55bc7
commit 526716329c
9 changed files with 178 additions and 18 deletions

2
6502.c
View File

@ -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

View 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

5
op.c
View File

@ -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:

View File

@ -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;
}

View File

@ -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);
}

54
rmac.c
View File

@ -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);
}
}

2
rmac.h
View File

@ -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;

106
symbol.c
View File

@ -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;
}

View File

@ -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__