Added preliminary sbdump code.
This commit is contained in:
parent
9f8f21c7bf
commit
d56bd81a0a
4 changed files with 364 additions and 0 deletions
15
sbdump/AssemblyInfo.cs
Normal file
15
sbdump/AssemblyInfo.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
[assembly: AssemblyTitle("sbdump")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("arookas")]
|
||||
[assembly: AssemblyProduct("sbdump")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2015 arookas")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: Guid("e2610ef0-cb2d-4f90-a18a-a2e7db316202")]
|
||||
[assembly: AssemblyVersion("0.1.0.0")]
|
||||
[assembly: AssemblyFileVersion("0.1.0.0")]
|
275
sbdump/main.cs
Normal file
275
sbdump/main.cs
Normal file
|
@ -0,0 +1,275 @@
|
|||
using arookas.IO.Binary;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace arookas {
|
||||
class sbdump {
|
||||
static CommandLineSettings sSettings;
|
||||
static aBinaryReader sReader;
|
||||
static TextWriter sWriter;
|
||||
static uint sTextOffset, sDataOffset, sDynsymOffset;
|
||||
static int sDataCount, sDynsymCount, sBssCount;
|
||||
|
||||
const string cTitle = "sbdump v0.1 arookas";
|
||||
static readonly string[] sSymbolTypes = { "builtin", "function", "var", };
|
||||
static readonly string[] sCommandNames = {
|
||||
"int", "flt", "str", "adr", "var", "nop", "inc", "dec",
|
||||
"add", "sub", "mul", "div", "mod", "ass", "eq", "ne",
|
||||
"gt", "lt", "ge", "le", "neg", "not", "and", "or",
|
||||
"band", "bor", "shl", "shr", "call", "func", "mkfr", "mkds",
|
||||
"ret", "ret0", "jne", "jmp", "pop", "int0", "int1", "end",
|
||||
};
|
||||
|
||||
static int Main(string[] args) {
|
||||
try {
|
||||
Console.WriteLine(cTitle);
|
||||
ReadCommandLine(args);
|
||||
Console.WriteLine("Opening input file...");
|
||||
using (var sb = File.OpenRead(sSettings.Input)) {
|
||||
CreateReader(sb);
|
||||
Console.WriteLine("Creating output file...");
|
||||
using (sWriter = File.CreateText(sSettings.Output)) {
|
||||
ReadHeader();
|
||||
WritePreamble();
|
||||
if (sSettings.OutputHeader) {
|
||||
WriteHeader();
|
||||
}
|
||||
if (sSettings.OutputText) {
|
||||
WriteText();
|
||||
}
|
||||
if (sSettings.OutputData) {
|
||||
WriteData();
|
||||
}
|
||||
if (sSettings.OutputDynsym) {
|
||||
WriteDynsym();
|
||||
}
|
||||
if (sSettings.OutputBss) {
|
||||
WriteBss();
|
||||
}
|
||||
Console.WriteLine("Closing output file...");
|
||||
}
|
||||
Console.WriteLine("Closing input file...");
|
||||
}
|
||||
Console.WriteLine("Done.");
|
||||
}
|
||||
catch (Exception e) {
|
||||
Console.WriteLine(e.Message);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ReadCommandLine(string[] args) {
|
||||
Console.WriteLine("Reading command line...");
|
||||
sSettings = new CommandLineSettings(new CommandLine(args));
|
||||
}
|
||||
static void CreateReader(Stream stream) {
|
||||
Console.WriteLine("Creating binary reader...");
|
||||
sReader = new aBinaryReader(stream, Endianness.Big, Encoding.GetEncoding(932));
|
||||
}
|
||||
static void WritePreamble() {
|
||||
Console.WriteLine("Writing preamble...");
|
||||
sWriter.WriteLine("# {0}", cTitle);
|
||||
sWriter.WriteLine("# {0}", DateTime.Now);
|
||||
sWriter.WriteLine("# {0}", Path.GetFileName(sSettings.Input));
|
||||
sWriter.WriteLine();
|
||||
}
|
||||
static void ReadHeader() {
|
||||
Console.WriteLine("Reading header...");
|
||||
if (sReader.Read32() != 0x53504342u) { // 'SPCB'
|
||||
throw new Exception("Invalid magic.");
|
||||
}
|
||||
sTextOffset = sReader.Read32();
|
||||
sDataOffset = sReader.Read32();
|
||||
sDataCount = sReader.ReadS32();
|
||||
sDynsymOffset = sReader.Read32();
|
||||
sDynsymCount = sReader.ReadS32();
|
||||
sBssCount = sReader.ReadS32();
|
||||
}
|
||||
static void WriteHeader() {
|
||||
Console.WriteLine("Outputting header...");
|
||||
sWriter.WriteLine("# Header information");
|
||||
sWriter.WriteLine("# .text offset : {0:X8}", sTextOffset);
|
||||
sWriter.WriteLine("# .data offset : {0:X8}", sDataOffset);
|
||||
sWriter.WriteLine("# .data count : {0}", sDataCount);
|
||||
sWriter.WriteLine("# .dynsym offset : {0:X8}", sDynsymOffset);
|
||||
sWriter.WriteLine("# .dynsym count : {0}", sDynsymCount);
|
||||
sWriter.WriteLine("# .bss count : {0}", sBssCount);
|
||||
sWriter.WriteLine();
|
||||
}
|
||||
static void WriteText() {
|
||||
Console.WriteLine("Outputting .text...");
|
||||
sWriter.WriteLine(".text");
|
||||
WriteText(0u);
|
||||
var symbols = new Symbol[sDynsymCount];
|
||||
for (var i = 0; i < sDynsymCount; ++i) {
|
||||
symbols[i] = FetchSymbol(i);
|
||||
}
|
||||
foreach (var symbol in symbols.Where(i => i.Type == SymbolType.Function).OrderBy(i => i.Data)) {
|
||||
sWriter.WriteLine("{0}: ", FetchSymbolName(symbol));
|
||||
WriteText(symbol.Data);
|
||||
}
|
||||
}
|
||||
static void WriteText(uint ofs) {
|
||||
byte command;
|
||||
sReader.Keep();
|
||||
sReader.Goto(sTextOffset + ofs);
|
||||
do {
|
||||
var pos = sReader.Position - sTextOffset;
|
||||
command = sReader.Read8();
|
||||
sWriter.Write(" {0:X8} {1}", pos, sCommandNames[command]);
|
||||
switch (command) {
|
||||
case 0x00: sWriter.Write(" {0}", sReader.ReadS32()); break;
|
||||
case 0x01: sWriter.Write(" {0}", sReader.ReadF32()); break;
|
||||
case 0x02: {
|
||||
var data = sReader.ReadS32();
|
||||
var value = FetchDataValue(data);
|
||||
sWriter.Write(" {0} # \"{1}\"", data, value);
|
||||
break;
|
||||
}
|
||||
case 0x03: sWriter.Write(" ${0:X8}", sReader.Read32()); break;
|
||||
case 0x04: {
|
||||
var display = sReader.ReadS32();
|
||||
sWriter.Write(" {0}", FetchSymbolName(FetchSymbol(sReader.ReadS32()))); break;
|
||||
}
|
||||
case 0x06: WriteVar(); break;
|
||||
case 0x07: WriteVar(); break;
|
||||
case 0x0D: {
|
||||
sReader.Read8(); // TSpcInterp skips this byte
|
||||
WriteVar();
|
||||
break;
|
||||
}
|
||||
case 0x1C: {
|
||||
var dest = sReader.Read32();
|
||||
var args = sReader.ReadS32();
|
||||
var symbol = FetchSymbol(i => i.Data == dest);
|
||||
if (symbol != null) {
|
||||
sWriter.Write(" {0}, {1}", FetchSymbolName(symbol), args);
|
||||
}
|
||||
else {
|
||||
sWriter.Write(" ${0:X8}, {1}", dest, args);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x1D: sWriter.Write(" {0}, {1}", FetchSymbolName(FetchSymbol(sReader.ReadS32())), sReader.ReadS32()); break;
|
||||
case 0x1E: sWriter.Write(" {0}", sReader.ReadS32()); break;
|
||||
case 0x1F: sWriter.Write(" {0}", sReader.ReadS32()); break;
|
||||
case 0x22: WriteJmp(ofs); break;
|
||||
case 0x23: WriteJmp(ofs); break;
|
||||
}
|
||||
sWriter.WriteLine();
|
||||
|
||||
} while (command != 0x21 && command != 0x27);
|
||||
sWriter.WriteLine();
|
||||
sReader.Back();
|
||||
}
|
||||
static void WriteVar() {
|
||||
var display = sReader.ReadS32();
|
||||
switch (display) {
|
||||
case 0: sWriter.Write(" {0}", FetchSymbolName(FetchSymbol(sReader.ReadS32()))); break;
|
||||
case 1: sWriter.Write(" locl{0}", sReader.ReadS32()); break;
|
||||
}
|
||||
}
|
||||
static void WriteJmp(uint ofs) {
|
||||
var dest = sReader.Read32();
|
||||
var symbol = FetchSymbol(i => i.Data == ofs);
|
||||
if (ofs > 0 && symbol != null) {
|
||||
var name = FetchSymbolName(symbol);
|
||||
sWriter.Write(" {0} + ${1:X4} # ${2:X8}", name, dest - ofs, ofs);
|
||||
}
|
||||
else {
|
||||
sWriter.Write(" ${0:X8}", dest);
|
||||
}
|
||||
}
|
||||
static void WriteData() {
|
||||
Console.WriteLine("Outputting .data...");
|
||||
sWriter.WriteLine(".data");
|
||||
sReader.Goto(sDataOffset);
|
||||
for (int i = 0; i < sDataCount; ++i) {
|
||||
var ofs = sReader.Read32();
|
||||
var data = FetchDataValue(ofs);
|
||||
sWriter.WriteLine(" .string \"{0}\"", data);
|
||||
}
|
||||
sWriter.WriteLine();
|
||||
}
|
||||
static void WriteDynsym() {
|
||||
Console.WriteLine("Outputting .dynsym...");
|
||||
sWriter.WriteLine(".dynsym");
|
||||
sReader.Goto(sDynsymOffset);
|
||||
for (int i = 0; i < sDynsymCount; ++i) {
|
||||
var symbol = new Symbol(sReader);
|
||||
var name = FetchSymbolName(symbol);
|
||||
sWriter.WriteLine(" .{0} {1}", sSymbolTypes[(int)symbol.Type], name);
|
||||
}
|
||||
sWriter.WriteLine();
|
||||
}
|
||||
static void WriteBss() {
|
||||
Console.WriteLine("Outputting .bss...");
|
||||
sWriter.WriteLine(".bss");
|
||||
for (int i = 0; i < sBssCount; ++i) {
|
||||
var symbol = FetchSymbol(j => j.Type == SymbolType.Variable && j.Data == i);
|
||||
if (symbol != null) {
|
||||
sWriter.WriteLine(" .var {0}", FetchSymbolName(symbol));
|
||||
}
|
||||
else {
|
||||
sWriter.WriteLine(" .var");
|
||||
}
|
||||
}
|
||||
sWriter.WriteLine();
|
||||
}
|
||||
|
||||
static uint FetchData(int i) {
|
||||
sReader.Keep();
|
||||
sReader.Goto(sDataOffset + (4 * i));
|
||||
var data = sReader.Read32();
|
||||
sReader.Back();
|
||||
return data;
|
||||
}
|
||||
static string FetchDataValue(int i) {
|
||||
if (i < 0 || i >= sDataCount) {
|
||||
return "null";
|
||||
}
|
||||
return FetchDataValue(FetchData(i));
|
||||
}
|
||||
static string FetchDataValue(uint ofs) {
|
||||
sReader.Keep();
|
||||
sReader.Goto(sDataOffset + (4 * sDataCount) + ofs);
|
||||
var data = sReader.ReadString(aBinaryStringFormat.NullTerminated);
|
||||
sReader.Back();
|
||||
return data;
|
||||
}
|
||||
static Symbol FetchSymbol(int i) {
|
||||
sReader.Keep();
|
||||
sReader.Goto(sDynsymOffset + (20 * i));
|
||||
var symbol = new Symbol(sReader);
|
||||
sReader.Back();
|
||||
return symbol;
|
||||
}
|
||||
static Symbol FetchSymbol(Predicate<Symbol> predicate) {
|
||||
if (predicate == null) {
|
||||
throw new ArgumentNullException("predicate");
|
||||
}
|
||||
Symbol found = null;
|
||||
sReader.Keep();
|
||||
sReader.Goto(sDynsymOffset);
|
||||
for (int i = 0; i < sDynsymCount; ++i) {
|
||||
var symbol = new Symbol(sReader);
|
||||
if (predicate(symbol)) {
|
||||
found = symbol;
|
||||
break;
|
||||
}
|
||||
}
|
||||
sReader.Back();
|
||||
return found;
|
||||
}
|
||||
static string FetchSymbolName(Symbol symbol) {
|
||||
sReader.Keep();
|
||||
sReader.Goto(sDynsymOffset + (20 * sDynsymCount) + symbol.StringOffset);
|
||||
var name = sReader.ReadString(aBinaryStringFormat.NullTerminated);
|
||||
sReader.Back();
|
||||
return name;
|
||||
}
|
||||
}
|
||||
}
|
45
sbdump/settings.cs
Normal file
45
sbdump/settings.cs
Normal file
|
@ -0,0 +1,45 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace arookas {
|
||||
class CommandLineSettings {
|
||||
string mInput, mOutput;
|
||||
bool mOutputHeader, mOutputText, mOutputData, mOutputDynsym, mOutputBss;
|
||||
|
||||
public string Input { get { return mInput; } }
|
||||
public string Output { get { return mOutput; } }
|
||||
public bool OutputHeader { get { return mOutputHeader; } }
|
||||
public bool OutputText { get { return mOutputText; } }
|
||||
public bool OutputData { get { return mOutputData; } }
|
||||
public bool OutputDynsym { get { return mOutputDynsym; } }
|
||||
public bool OutputBss { get { return mOutputBss; } }
|
||||
|
||||
public CommandLineSettings(CommandLine cmd) {
|
||||
if (cmd == null) {
|
||||
throw new ArgumentNullException("cmd");
|
||||
}
|
||||
foreach (var param in cmd) {
|
||||
switch (param.Name) {
|
||||
case "-in": mInput = param[0]; continue;
|
||||
case "-out": mInput = param[0]; continue;
|
||||
case "-H": mOutputHeader = true; continue;
|
||||
case "-h": mOutputHeader = false; continue;
|
||||
case "-T": mOutputText = true; continue;
|
||||
case "-t": mOutputText = false; continue;
|
||||
case "-D": mOutputData = true; continue;
|
||||
case "-d": mOutputData = false; continue;
|
||||
case "-S": mOutputDynsym = true; continue;
|
||||
case "-s": mOutputDynsym = false; continue;
|
||||
case "-B": mOutputBss = true; continue;
|
||||
case "-b": mOutputBss = false; continue;
|
||||
}
|
||||
}
|
||||
if (mInput == null) {
|
||||
throw new Exception("Missing input file setting.");
|
||||
}
|
||||
if (mOutput == null) {
|
||||
mOutput = Path.ChangeExtension(mInput, ".txt");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
29
sbdump/symbol.cs
Normal file
29
sbdump/symbol.cs
Normal file
|
@ -0,0 +1,29 @@
|
|||
using arookas.IO.Binary;
|
||||
|
||||
namespace arookas {
|
||||
class Symbol {
|
||||
SymbolType mType;
|
||||
uint mStringOffset;
|
||||
uint mData;
|
||||
// NOTE: the other two fields are runtime fields (hash and linker storage)
|
||||
|
||||
public SymbolType Type { get { return mType; } }
|
||||
public uint StringOffset { get { return mStringOffset; } }
|
||||
public uint Data { get { return mData; } }
|
||||
|
||||
public Symbol(aBinaryReader reader) {
|
||||
mType = (SymbolType)reader.Read32();
|
||||
mStringOffset = reader.Read32();
|
||||
mData = reader.Read32();
|
||||
// skip the last two fields
|
||||
reader.Read32();
|
||||
reader.Read32();
|
||||
}
|
||||
}
|
||||
|
||||
enum SymbolType {
|
||||
Builtin,
|
||||
Function,
|
||||
Variable,
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue