diff --git a/smxdasm/File.cs b/smxdasm/File.cs index ac7c844..a175fc3 100644 --- a/smxdasm/File.cs +++ b/smxdasm/File.cs @@ -1,4 +1,5 @@ -using System.IO; +using System; +using System.IO; using System.Collections.Generic; namespace smxdasm @@ -22,6 +23,8 @@ public class SmxFile public SmxDebugNativesTable DebugNatives; public SmxDebugSymbolsTable DebugSymbols; + public SmxCalledFunctionsTable CalledFunctions; + public SmxFile(BinaryReader br) { Header = FileHeader.From(br); @@ -36,7 +39,9 @@ public SmxFile(BinaryReader br) else if (section.Name == ".dbg.info") DebugInfo = new SmxDebugInfoSection(Header, section); } - + + CalledFunctions = new SmxCalledFunctionsTable(); + // Parse out other sections. var unknown = new List(); foreach (var section in Header.Sections) @@ -83,6 +88,53 @@ public SmxFile(BinaryReader br) } } UnknownSections = unknown.ToArray(); + + // Disassemble all functions right away to find all called functions. + if (DebugSymbols != null) + { + foreach (var entry in DebugSymbols.Entries) + { + if (entry.Ident != SymKind.Function) + continue; + + try + { + V1Disassembler.Disassemble(this, CodeV1, entry.Address); + } + catch (Exception) + { + continue; + } + } + } + if (Publics != null) + { + foreach (var pubfun in Publics.Entries) + { + try + { + V1Disassembler.Disassemble(this, CodeV1, (int)pubfun.Address); + } + catch (Exception) + { + continue; + } + } + } + if (CalledFunctions != null) + { + foreach (var fun in CalledFunctions.Entries) + { + try + { + V1Disassembler.Disassemble(this, CodeV1, (int)fun.Address); + } + catch (Exception) + { + continue; + } + } + } } public string FindFunctionName(int address) @@ -101,6 +153,14 @@ public string FindFunctionName(int address) return pubfun.Name; } } + if (CalledFunctions != null) + { + foreach (var fun in CalledFunctions.Entries) + { + if (fun.Address == address) + return fun.Name; + } + } return "(unknown)"; } } diff --git a/smxdasm/Sections.cs b/smxdasm/Sections.cs index 0aadb69..333e200 100644 --- a/smxdasm/Sections.cs +++ b/smxdasm/Sections.cs @@ -142,6 +142,39 @@ public PublicEntry this[int index] } } + public class SmxCalledFunctionsTable + { + private List functions_; + + public SmxCalledFunctionsTable() + { + functions_ = new List(); + } + + public CalledFunctionEntry[] Entries + { + get { return functions_.ToArray(); } + } + + public int Length + { + get { return functions_.Count; } + } + + public CalledFunctionEntry this[int index] + { + get { return functions_[index]; } + } + + public void AddFunction(uint addr) + { + var entry = new CalledFunctionEntry(); + entry.Address = addr; + entry.Name = String.Format("sub_{0:x}", addr); + functions_.Add(entry); + } + } + // The .pubvars table. public class SmxPubvarTable : SmxSection { diff --git a/smxdasm/V1Disassembler.cs b/smxdasm/V1Disassembler.cs index 6fec329..824b5e5 100644 --- a/smxdasm/V1Disassembler.cs +++ b/smxdasm/V1Disassembler.cs @@ -180,6 +180,7 @@ static V1Disassembler() Prep(V1Opcode.ZERO_S, V1Param.Stack); } + private SmxFile file_; private byte[] data_; private int code_start_; private int proc_offset_; @@ -205,6 +206,7 @@ private V1Opcode readNextOp() private V1Disassembler(SmxFile file, SmxCodeV1Section code, int proc_offset) { + file_ = file; data_ = file.Header.Data; code_start_ = code.CodeStart; proc_offset_ = proc_offset; @@ -247,6 +249,14 @@ private V1Instruction[] disassemble() insn.Params = new int[insn.Info.Params.Length]; for (var i = 0; i < insn.Info.Params.Length; i++) insn.Params[i] = readNext(); + + // Catch calls to unknown functions so they can be disassembled easily too. + if (op == (int)V1Opcode.CALL) + { + var addr = insn.Params[0]; + if (file_.FindFunctionName(addr) == "(unknown)") + file_.CalledFunctions.AddFunction((uint)addr); + } } return insns.ToArray(); } diff --git a/smxdasm/V1Types.cs b/smxdasm/V1Types.cs index bb6664c..e2fc349 100644 --- a/smxdasm/V1Types.cs +++ b/smxdasm/V1Types.cs @@ -103,6 +103,13 @@ public static PublicEntry[] From(BinaryReader rd, SectionEntry header, SmxNameTa } } + // Called functions that weren't in the .publics or .dbg.symbols sections. + public class CalledFunctionEntry + { + public uint Address; + public string Name; + } + // The ".natives" section. public class NativeEntry { diff --git a/smxviewer/MainWindow.cs b/smxviewer/MainWindow.cs index a9970f2..8de9e47 100644 --- a/smxviewer/MainWindow.cs +++ b/smxviewer/MainWindow.cs @@ -499,6 +499,13 @@ private void renderCodeSection(TreeNode root, SmxCodeV1Section code) functionMap[sym.Name] = sym.CodeStart; } } + if (file_.CalledFunctions != null) + { + foreach (var fun in file_.CalledFunctions.Entries) + { + functionMap[fun.Name] = fun.Address; + } + } foreach (var pair in functionMap) {