DEBUG printf("inf[op][amode]=%d\n", (int)inf[op][amode]);
#endif
+ GENLINENOSYM();
+
switch (inf[op][amode])
{
case A65_IMPL: // Just leave the instruction
-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.
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
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:
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;
}
// Call special-mode handler
if (m->mnattr & CGSPECIAL)
{
+ GENLINENOSYM();
(*m->mnfunc)(m->mninst, siz);
goto loop;
}
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;
}
}
int value = ((opcode & 0x3F) << 10) + ((reg1 & 0x1F) << 5) + (reg2 & 0x1F);
+ GENLINENOSYM();
D_word(value);
}
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
" 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"
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];
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
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':
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':
}
else
{
- // Record first filename.
- if (firstfname == NULL)
- firstfname = argv[argno];
-
strcpy(fnbuf, argv[argno]);
fext(fnbuf, ".s", 0);
fd = open(fnbuf, 0);
continue;
}
- include(fd, fnbuf);
- Assemble();
+ ProcessFile(fd, fnbuf);
}
}
#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
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;
//
// 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;
//
// 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));
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);
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;
+}
// 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);
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__