diff --git a/.gitignore b/.gitignore
index 145d8a0..ee2e9b3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -19,4 +19,5 @@
*.obj.enc
*.user
*.db*
+*.recipe
test/results/*
\ No newline at end of file
diff --git a/README.md b/README.md
index 29a954c..d9d1797 100644
--- a/README.md
+++ b/README.md
@@ -102,6 +102,7 @@ Primarily tested with personal archive of sources written for Kick assmebler, DA
* irp (indefinite repeat)
**FIXED**
+* Source Debug output file including linkable object files, C64Debugger format
* Adding MERGE directive, Label Pools rewrite, TEXT data can be indexed from a string symbol
* Label Pools were destroyed after each scope so they did not work in include files which defeated their purpose. Label pools are now persistent through scopes.
* Labels reserved from label pools now distinguish between global and local. Use [.!@$] as a prefix to reserve a local label from a label pool (previously always local)
diff --git a/obj/x64Releasedump_x65/dump_x65.vcxproj.FileListAbsolute.txt b/obj/x64Releasedump_x65/dump_x65.vcxproj.FileListAbsolute.txt
new file mode 100644
index 0000000..e69de29
diff --git a/obj/x64Releasex65/x65.vcxproj.FileListAbsolute.txt b/obj/x64Releasex65/x65.vcxproj.FileListAbsolute.txt
new file mode 100644
index 0000000..e69de29
diff --git a/sln/dump_x65/dump_x65.vcxproj b/sln/dump_x65/dump_x65.vcxproj
index 996b984..433d851 100644
--- a/sln/dump_x65/dump_x65.vcxproj
+++ b/sln/dump_x65/dump_x65.vcxproj
@@ -23,32 +23,32 @@
{57EFF4A4-7BF2-43F0-AD62-A79092DA67D1}
Win32Proj
dump_x65
- 10.0.15063.0
+ 10.0
Application
true
- v141
+ v142
NotSet
Application
false
- v141
+ v142
true
NotSet
Application
true
- v141
+ v142
NotSet
Application
false
- v141
+ v142
true
NotSet
diff --git a/sln/x65.vcxproj b/sln/x65.vcxproj
index 5568169..8ab13a3 100644
--- a/sln/x65.vcxproj
+++ b/sln/x65.vcxproj
@@ -23,32 +23,32 @@
{2823019A-A423-4A40-BB9C-5CE242019BD0}
Win32Proj
x65
- 10.0.15063.0
+ 10.0
Application
true
- v141
+ v142
NotSet
Application
false
- v141
+ v142
true
NotSet
Application
true
- v141
+ v142
NotSet
Application
false
- v141
+ v142
true
NotSet
diff --git a/x65.cpp b/x65.cpp
index cdabb0c..de97ecb 100644
--- a/x65.cpp
+++ b/x65.cpp
@@ -47,6 +47,7 @@
// Command line arguments
static const strref cmdarg_listing("lst"); // -lst / -lst=(file.lst) : generate disassembly text from result(file or stdout)
+static const strref cmdarg_srcdebug("srcdbg"); // -srcdbg : generate debug, -srcdbg=(file) : save debug file
static const strref cmdarg_tass_listing("tsl"); // -tsl=(file) : generate listing file in TASS style
static const strref cmdarg_tass_labels("tl"); // -tl=(file) : generate labels in TASS style
static const strref cmdarg_allinstr("opcodes"); // -opcodes / -opcodes=(file.s) : dump all available opcodes(file or stdout)
@@ -1133,6 +1134,13 @@ uint32_t FindLabelIndex(uint32_t hash, uint32_t *table, uint32_t count)
return count;
}
+char* StringCopy(strref str)
+{
+ char* buf = (char*)calloc(1, (size_t)str.get_len() + 1);
+ if (buf && str.get_len()) { memcpy(buf, str.get(), str.get_len()); }
+ return buf;
+}
+
//
@@ -1431,7 +1439,7 @@ struct SourceDebugEntry {
int size;
int source_file_offset; // can be converted into line/column while linking
};
-typedef std::vector SourceDebug;
+typedef std::vector SourceDebug;
enum SectionType : int8_t { // enum order indicates fixed address linking priority
@@ -1513,6 +1521,8 @@ typedef struct Section {
pRelocs = nullptr;
if (pListing) delete pListing;
pListing = nullptr;
+ if (pSrcDbg) delete pSrcDbg;
+ pSrcDbg = nullptr;
}
void Cleanup() { if (output) free(output); reset(); }
@@ -1536,11 +1546,11 @@ typedef struct Section {
void AddReloc(int base, int offset, int section, int8_t bytes, int8_t shift);
Section() : pRelocs(nullptr), pListing(nullptr) { reset(); }
- Section(strref _name, int _address) : pRelocs(nullptr), pListing(nullptr) {
+ Section(strref _name, int _address) : pRelocs(nullptr), pListing(nullptr), pSrcDbg(nullptr) {
reset(); name = _name; start_address = load_address = address = _address;
address_assigned = true;
}
- Section(strref _name) : pRelocs(nullptr), pListing(nullptr) {
+ Section(strref _name) : pRelocs(nullptr), pListing(nullptr), pSrcDbg(nullptr) {
reset(); name = _name;
start_address = load_address = address = 0; address_assigned = false;
}
@@ -1819,6 +1829,7 @@ public:
int8_t cycle_counter_level; // merlin toggles the cycle counter rather than hierarchically evals
bool error_encountered; // if any error encountered, don't export binary
bool list_assembly; // generate assembler listing
+ bool src_debug; // generate source debug info
bool end_macro_directive; // whether to use { } or macro / endmacro for macro scope
bool import_means_xref;
@@ -1835,6 +1846,9 @@ public:
// Mimic TASS listing
bool ListTassStyle( strref filename );
+ // Export C64Debugger dbg xml file
+ bool SourceDebugExport(strref filename);
+
// Generate source for all valid instructions and addressing modes for current CPU
bool AllOpcodes(strref filename);
@@ -2034,9 +2048,7 @@ void SymbolStackTable::PushSymbol(StringSymbol* string)
ValueOrString val;
val.string = nullptr;
if (string->string_value) {
- val.string = (char*)malloc(string->string_value.get_len() + 1);
- memcpy(val.string, string->string_value.get(), string->string_value.get_len());
- val.string[string->string_value.get_len()] = 0;
+ val.string = StringCopy(string->string_value.get_strref());
}
(*ppStack)->push_back(val);
}
@@ -2143,8 +2155,12 @@ void Asm::Cleanup() {
free(str.string_value.charstr());
}
strings.clear();
- for (std::vector::iterator exti = externals.begin(); exti !=externals.end(); ++exti)
+ for (std::vector::iterator exti = externals.begin(); exti != externals.end(); ++exti) {
exti->labels.clear();
+ }
+ for (std::vector::iterator src = source_files.begin(); src != source_files.end(); ++src) {
+ free(*src);
+ }
externals.clear();
// this section is relocatable but is assigned address $1000 if exporting without directives
SetSection(strref("default,code"));
@@ -2159,6 +2175,7 @@ void Asm::Cleanup() {
directive_scope_depth = 0;
error_encountered = false;
list_assembly = false;
+ src_debug = false;
end_macro_directive = false;
import_means_xref = false;
accumulator_16bit = false; // default 65816 8 bit immediate mode
@@ -2921,6 +2938,20 @@ StatusCode Asm::MergeSections(int section_id, int section_merge) {
delete m.pListing;
m.pListing = nullptr;
}
+ // go through source debug
+ if (m.pSrcDbg) {
+ if (!s.pSrcDbg) { s.pSrcDbg = new SourceDebug; }
+ if (s.pSrcDbg->capacity() < (m.pSrcDbg->size() + s.pSrcDbg->size())) {
+ s.pSrcDbg->reserve((m.pSrcDbg->size() + s.pSrcDbg->size()));
+ }
+ for (SourceDebug::iterator i = m.pSrcDbg->begin(); i != m.pSrcDbg->end(); ++i) {
+ SourceDebugEntry l = *i;
+ l.address += addr_start;
+ s.pSrcDbg->push_back(l);
+ }
+ delete m.pSrcDbg;
+ m.pSrcDbg = nullptr;
+ }
m.type = ST_REMOVED;
return STATUS_OK;
}
@@ -6707,24 +6738,43 @@ StatusCode Asm::BuildLine(strref line) {
}
}
// update listing
- if (error == STATUS_OK && list_assembly) {
+ if (error == STATUS_OK) {
if (SectionId() == start_section) {
Section &curr = CurrSection();
- if (!curr.pListing) { curr.pListing = new Listing; }
- if (curr.pListing && curr.pListing->size()==curr.pListing->capacity()) {
- curr.pListing->reserve(curr.pListing->size()+256);
- }
- if (((list_flags&(ListLine::KEYWORD|ListLine::CYCLES_START|ListLine::CYCLES_STOP)) ||
+ if (list_assembly) {
+ if (!curr.pListing) { curr.pListing = new Listing; }
+ if (((list_flags & (ListLine::KEYWORD | ListLine::CYCLES_START | ListLine::CYCLES_STOP)) ||
(curr.address != start_address && curr.size())) && !curr.IsDummySection()) {
- struct ListLine lst;
- lst.address = start_address - curr.start_address;
- lst.size = curr.address - start_address;
- lst.code = contextStack.curr().source_file;
- lst.column = (uint16_t)(data_line - code_line.get());
- lst.source_name = contextStack.curr().source_name;
- lst.line_offs = int(code_line.get() - lst.code.get());
- lst.flags = list_flags;
- curr.pListing->push_back(lst);
+ struct ListLine lst;
+ lst.address = start_address - curr.start_address;
+ lst.size = curr.address - start_address;
+ lst.code = contextStack.curr().source_file;
+ lst.column = (uint16_t)(data_line - code_line.get());
+ lst.source_name = contextStack.curr().source_name;
+ lst.line_offs = int(code_line.get() - lst.code.get());
+ lst.flags = list_flags;
+ curr.pListing->push_back(lst);
+ }
+ }
+ if (src_debug) {
+ if (!curr.pSrcDbg) { curr.pSrcDbg = new SourceDebug; }
+ if (curr.address != start_address && curr.size()) {
+ SourceDebugEntry entry;
+ entry.address = start_address - curr.start_address;
+ entry.size = curr.address - start_address;
+
+ size_t sf = 0, nsf = source_files.size();
+ strref src = contextStack.curr().source_name;
+ for (; sf < nsf; ++sf) {
+ if (src.same_str_case(source_files[sf])) { break; }
+ }
+ if (sf == nsf) {
+ source_files.push_back(StringCopy(src));
+ }
+ entry.source_file_index = (int)sf;
+ entry.source_file_offset = (int)(data_line - contextStack.curr().source_file.get());
+ curr.pSrcDbg->push_back(entry);
+ }
}
}
}
@@ -6888,6 +6938,95 @@ bool Asm::ListTassStyle( strref filename ) {
return true;
}
+bool Asm::SourceDebugExport(strref filename) {
+ FILE* f = stdout;
+ bool opened = false;
+ if (filename) {
+ f = fopen(strown<512>(filename).c_str(), "w");
+ if (!f) { return false; }
+ opened = true;
+ } else {
+ return false;
+ }
+
+ std::vector source_code; source_code.reserve(source_files.size());
+
+ fprintf(f, "\n\t\n");
+ for (size_t i = 0, n = source_files.size(); i < n; ++i) {
+ fprintf(f, "\t\t%d,%s\n", (int)i+1, source_files[i]);
+
+ size_t size = 0;
+ char* src = LoadText(source_files[i], size);
+ source_code.push_back(strovl(src, (strl_t)size, (strl_t)size));
+ }
+ fprintf(f, "\t\n\n");
+
+ for (size_t i = 0, n = allSections.size(); i < n; ++i) {
+ Section& s = allSections[i];
+ if (s.pSrcDbg && s.pSrcDbg->size()) {
+ fprintf(f, "\t\n\t\t\n",
+ STRREF_ARG(s.name));
+ for (size_t d = 0, nd = s.pSrcDbg->size(); d < nd; ++d) {
+ SourceDebugEntry& e = s.pSrcDbg->at(d);
+ int line = 0, col0 = 0, col1 = 0;
+ if ((e.source_file_index) < source_code.size()) {
+ strref src = source_code[e.source_file_index].get_strref();
+ if (src.get_len() > strl_t(e.source_file_offset)) {
+ line = strref(src.get(), e.source_file_offset).count_lines();
+ strl_t offs = e.source_file_offset;
+ while (src.get_at(offs) != 0x0a && src.get_at(offs) != 0x0d && offs) { --offs; ++col0; }
+ col1 = col0;
+ offs = e.source_file_offset;
+ while (src.get_at(offs) != 0x0a && src.get_at(offs) != 0x0d && offs\n\t\n\n");
+ }
+ }
+
+ fprintf(f, "\t\n");
+ for (MapSymbolArray::iterator i = map.begin(); i != map.end(); ++i) {
+ if (i->name.same_str("debugbreak")) { continue; }
+ uint32_t value = (uint32_t)i->value;
+ strref sectName;
+ if (size_t(i->section) < allSections.size()) {
+ value += allSections[i->section].start_address;
+ sectName = allSections[i->section].name;
+ }
+ fprintf(f, "\t\t" STRREF_FMT ",$%04x," STRREF_FMT ",0,0,0,0,0\n", STRREF_ARG(sectName), value, STRREF_ARG(i->name));
+ }
+ fprintf(f, "\t\n\n");
+
+ fprintf(f, "\t\n");
+ for (MapSymbolArray::iterator i = map.begin(); i != map.end(); ++i) {
+ uint32_t value = (uint32_t)i->value;
+ strref sectName;
+ if (size_t(i->section) < allSections.size()) {
+ value += allSections[i->section].start_address;
+ sectName = allSections[i->section].name;
+ }
+ if (i->name.same_str("debugbreak")) {
+ fprintf(f, "\t\t" STRREF_FMT ",$%04x,\n", STRREF_ARG(sectName), value);
+ }
+ }
+ fprintf(f, "\t\n\n");
+
+ fprintf(f, "\t\n");
+ fprintf(f, "\t\n\n");
+
+ fprintf(f, "\n");
+ fclose(f);
+
+ for (size_t i = 0, n = source_code.size(); i < n; ++i) {
+ if (source_code[i].get()) { free(source_code[i].charstr()); }
+ }
+ return true;
+}
+
bool Asm::List(strref filename) {
FILE *f = stdout;
bool opened = false;
@@ -7205,6 +7344,7 @@ struct ObjFileHeader {
int16_t late_evals;
int16_t map_symbols;
uint32_t stringdata;
+ uint32_t srcdebug;
int bindata;
};
@@ -7224,7 +7364,7 @@ struct ObjFileSection {
int end_address; // address size
int output_size; // assembled binary size
int align_address;
- int list_count; // how many addresses included in debugger listing
+ int srcdebug_count; // how many addresses included in debugger listing
int16_t next_group; // next section of group
int16_t first_group; // first section of group
int16_t relocs;
@@ -7279,10 +7419,11 @@ struct ObjFileMapSymbol {
// this struct is follwed by numSources x ObjFileStr
struct ObjFileSourceList {
uint32_t numSources;
+ ObjFileStr sourceFile[1];
};
// after that one long array of all sections worth of source references
-struct ObjFileSrcRef {
+struct ObjFileSrcDbg {
uint16_t addr; // relative to section
uint16_t src_idx;
uint16_t size;
@@ -7360,6 +7501,7 @@ StatusCode Asm::WriteObjectFile(strref filename) {
hdr.late_evals = (int16_t)lateEval.size();
hdr.map_symbols = (int16_t)map.size();
hdr.stringdata = 0;
+ hdr.srcdebug = 0;
// labels don't include XREF labels
hdr.labels = 0;
@@ -7380,7 +7522,7 @@ StatusCode Asm::WriteObjectFile(strref filename) {
char *stringPool = nullptr;
uint32_t stringPoolCap = 0;
pairArray stringArray;
- stringArray.reserve(hdr.labels * 2 + hdr.sections + hdr.late_evals*2);
+ stringArray.reserve(hdr.labels * 2 + hdr.sections + hdr.late_evals*2 + (uint32_t)source_files.size());
struct ObjFileSection *aSects = hdr.sections ? (struct ObjFileSection*)calloc(hdr.sections, sizeof(struct ObjFileSection)) : nullptr;
struct ObjFileReloc *aRelocs = hdr.relocs ? (struct ObjFileReloc*)calloc(hdr.relocs, sizeof(struct ObjFileReloc)) : nullptr;
@@ -7398,11 +7540,11 @@ StatusCode Asm::WriteObjectFile(strref filename) {
}
sect = 0;
+ uint32_t srcDbgEntries = 0;
// write out sections and relocs
if (hdr.sections) {
for (std::vector::iterator si = allSections.begin(); si!=allSections.end(); ++si) {
- if (si->type == ST_REMOVED)
- continue;
+ if (si->type == ST_REMOVED) { continue; }
struct ObjFileSection &s = aSects[sect++];
s.name.offs = _AddStrPool(si->name, &stringArray, &stringPool, hdr.stringdata, stringPoolCap);
s.exp_app.offs = _AddStrPool(si->export_append, &stringArray, &stringPool, hdr.stringdata, stringPoolCap);
@@ -7411,6 +7553,8 @@ StatusCode Asm::WriteObjectFile(strref filename) {
s.next_group = si->next_group >= 0 ? aRemapSects[si->next_group] : -1;
s.first_group = si->first_group >= 0 ? aRemapSects[si->first_group] : -1;
s.relocs = si->pRelocs ? (int16_t)(si->pRelocs->size()) : 0;
+ s.srcdebug_count = si->pSrcDbg ? (int)si->pSrcDbg->size() : 0;
+ srcDbgEntries += s.srcdebug_count;
s.start_address = si->start_address;
s.end_address = si->address;
s.type = si->type;
@@ -7432,6 +7576,25 @@ StatusCode Asm::WriteObjectFile(strref filename) {
}
hdr.sections = (int16_t)sect;
+ struct ObjFileSrcDbg* srcLines = srcDbgEntries ? (ObjFileSrcDbg*)calloc(1, sizeof(ObjFileSrcDbg) * srcDbgEntries) : nullptr;
+ if (srcLines) {
+ size_t srcDbgIdx = 0;
+ for (std::vector::iterator si = allSections.begin(); si != allSections.end(); ++si) {
+ if (si->type == ST_REMOVED) { continue; }
+ if (si->pSrcDbg && si->pSrcDbg->size()) {
+ for (size_t src = 0, nsrc = si->pSrcDbg->size(); src < nsrc; ++src) {
+ SourceDebugEntry& entry = si->pSrcDbg->at(src);
+ ObjFileSrcDbg& ref = srcLines[srcDbgIdx++];
+ ref.addr = entry.address;
+ ref.src_idx = entry.source_file_index;
+ ref.size = entry.size;
+ ref.file_offs = entry.source_file_offset;
+ }
+ }
+ }
+ assert(srcDbgIdx == srcDbgEntries);
+ }
+
// write out labels
if (hdr.labels) {
for (uint32_t li = 0; linumSources = (uint32_t)source_files.size();
+ for (size_t src = 0, nsrc = source_files.size(); src < nsrc; ++src) {
+ sourceList->sourceFile[src].offs = _AddStrPool(strref(source_files[src]), &stringArray, &stringPool, hdr.stringdata, stringPoolCap);
+ }
+ }
+
+ hdr.srcdebug = srcDbgEntries;
+
// write out the file
fwrite(&hdr, sizeof(hdr), 1, f);
fwrite(aSects, sizeof(aSects[0]), sect, f);
@@ -7511,6 +7685,12 @@ StatusCode Asm::WriteObjectFile(strref filename) {
fwrite(si->output, si->size(), 1, f);
}
}
+ if (sourceList) {
+ fwrite(sourceList, sizeof(ObjFileSourceList) + sizeof(ObjFileStr) * (source_files.size() - 1), 1, f);
+ fwrite(srcLines, sizeof(ObjFileSrcDbg) * srcDbgEntries, 1, f);
+ }
+
+
// done with I/O
fclose(f);
if (aRemapSects) { free(aRemapSects); }
@@ -7539,6 +7719,14 @@ StatusCode Asm::ReadObjectFile(strref filename, int link_to_section)
hdr.relocs * sizeof(struct ObjFileReloc) + hdr.labels * sizeof(struct ObjFileLabel) +
hdr.late_evals * sizeof(struct ObjFileLateEval) +
hdr.map_symbols * sizeof(struct ObjFileMapSymbol) + hdr.stringdata + hdr.bindata;
+ const struct ObjFileSourceList* pSrcDbgInfo = hdr.srcdebug ? (struct ObjFileSourceList*)(data + sum) : nullptr;
+ const struct ObjFileSrcDbg* pSrcDbgEntry = pSrcDbgInfo ? (const struct ObjFileSrcDbg*)(pSrcDbgInfo->sourceFile + pSrcDbgInfo->numSources) : nullptr;
+
+ if (pSrcDbgInfo) {
+ sum += sizeof(ObjFileSourceList) + (pSrcDbgInfo->numSources - 1) * sizeof(ObjFileStr);
+ sum += sizeof(ObjFileSrcDbg) * hdr.srcdebug;
+ }
+
if (hdr.id == 0x7836 && sum == size) {
struct ObjFileSection *aSect = (struct ObjFileSection*)(&hdr + 1);
struct ObjFileReloc *aReloc = (struct ObjFileReloc*)(aSect + hdr.sections);
@@ -7552,6 +7740,23 @@ StatusCode Asm::ReadObjectFile(strref filename, int link_to_section)
memcpy(str_pool, str_orig, hdr.stringdata);
loadedData.push_back(str_pool);
+ // source files
+ std::vector source_file_remap;
+ if (pSrcDbgInfo) {
+ source_file_remap.reserve(pSrcDbgInfo->numSources);
+ for (size_t s = 0, n = pSrcDbgInfo->numSources; s < n; ++s) {
+ strref source_file(str_pool + pSrcDbgInfo->sourceFile[s].offs);
+ size_t i = 0, sz = source_files.size();
+ for (; i < sz; ++i) {
+ if (source_file.same_str(source_files[i])) { break; }
+ }
+ if (i == sz) {
+ source_files.push_back(StringCopy(source_file));
+ }
+ source_file_remap.push_back(i);
+ }
+ }
+
int prevSection = SectionId();
int16_t *aSctRmp = (int16_t*)malloc(hdr.sections * sizeof(int16_t));
int last_linked_section = link_to_section;
@@ -7596,6 +7801,19 @@ StatusCode Asm::ReadObjectFile(strref filename, int link_to_section)
s.first_group = allSections[last_linked_section].first_group >=0 ? allSections[last_linked_section].first_group : last_linked_section;
last_linked_section = SectionId();
}
+ // add source debug entries from object file
+ if (aSect[si].srcdebug_count) {
+ if (!s.pSrcDbg) { s.pSrcDbg = new SourceDebug; }
+ for (int sd = 0, nsd = aSect[si].srcdebug_count; sd < nsd; ++sd) {
+ SourceDebugEntry entry;
+ entry.address = pSrcDbgEntry->addr;
+ entry.size = pSrcDbgEntry->size;
+ entry.source_file_index = (int)source_file_remap[pSrcDbgEntry->src_idx];
+ entry.source_file_offset = pSrcDbgEntry->file_offs;
+ s.pSrcDbg->push_back(entry);
+ ++pSrcDbgEntry;
+ }
+ }
}
aSctRmp[si] = (int16_t)allSections.size()-1;
}
@@ -7978,6 +8196,7 @@ int main(int argc, char **argv) {
const char *sym_file = nullptr, *vs_file = nullptr, *cmdarg_tass_labels_file = nullptr;
strref list_file, allinstr_file;
strref tass_list_file;
+ strref srcdebug_file;
for (int a = 1; a