From 59ccfdd999452b0e02ae25d7ac12ba49e8d619f1 Mon Sep 17 00:00:00 2001 From: Ben Vanik Date: Sun, 3 Feb 2013 03:34:43 -0800 Subject: [PATCH] Read and write map files. --- include/xenia/cpu/sdb/symbol.h | 11 +- include/xenia/cpu/sdb/symbol_database.h | 11 +- private/runtest.sh | 3 + src/cpu/codegen/function_generator.cc | 6 +- src/cpu/codegen/module_generator.cc | 6 +- src/cpu/cpu-private.h | 2 + src/cpu/cpu.cc | 9 +- src/cpu/exec_module.cc | 9 +- src/cpu/llvm_exports.cc | 2 +- src/cpu/processor.cc | 2 - src/cpu/sdb/symbol.cc | 35 +++- src/cpu/sdb/symbol_database.cc | 247 ++++++++++++++++-------- src/cpu/sdb/xex_symbol_database.cc | 8 +- 13 files changed, 240 insertions(+), 111 deletions(-) diff --git a/include/xenia/cpu/sdb/symbol.h b/include/xenia/cpu/sdb/symbol.h index 5d5ed4174..b132436d2 100644 --- a/include/xenia/cpu/sdb/symbol.h +++ b/include/xenia/cpu/sdb/symbol.h @@ -49,12 +49,17 @@ public: ExceptionEntry = 2, }; - virtual ~Symbol() {} + virtual ~Symbol(); SymbolType symbol_type; + const char* name(); + void set_name(const char* value); + protected: - Symbol(SymbolType type) : symbol_type(type) {} + Symbol(SymbolType type); + + char* name_; }; class ExceptionEntrySymbol; @@ -105,7 +110,6 @@ public: uint32_t start_address; uint32_t end_address; - char* name; FunctionType type; uint32_t flags; @@ -125,7 +129,6 @@ public: virtual ~VariableSymbol(); uint32_t address; - char* name; kernel::KernelExport* kernel_export; }; diff --git a/include/xenia/cpu/sdb/symbol_database.h b/include/xenia/cpu/sdb/symbol_database.h index 8cc513bbd..1e3d49188 100644 --- a/include/xenia/cpu/sdb/symbol_database.h +++ b/include/xenia/cpu/sdb/symbol_database.h @@ -32,22 +32,23 @@ public: virtual int Analyze(); + Symbol* GetSymbol(uint32_t address); ExceptionEntrySymbol* GetOrInsertExceptionEntry(uint32_t address); FunctionSymbol* GetOrInsertFunction(uint32_t address); VariableSymbol* GetOrInsertVariable(uint32_t address); FunctionSymbol* GetFunction(uint32_t address); VariableSymbol* GetVariable(uint32_t address); - Symbol* GetSymbol(uint32_t address); int GetAllVariables(std::vector& variables); int GetAllFunctions(std::vector& functions); - void Write(const char* file_name); - void Dump(); - void DumpFunctionBlocks(FunctionSymbol* fn); + void ReadMap(const char* file_name); + void WriteMap(const char* file_name); + void Dump(FILE* file); + void DumpFunctionBlocks(FILE* file, FunctionSymbol* fn); protected: - typedef std::tr1::unordered_map SymbolMap; + typedef std::map SymbolMap; typedef std::list FunctionList; int AnalyzeFunction(FunctionSymbol* fn); diff --git a/private/runtest.sh b/private/runtest.sh index af3e573ee..e1f54ba0b 100755 --- a/private/runtest.sh +++ b/private/runtest.sh @@ -8,6 +8,9 @@ fi ./build/xenia/release/xenia-run \ private/$1 \ + --dump_path=build/ \ + --dump_module_map=true \ + --dump_module_bitcode=true \ --optimize_ir_modules=true \ --optimize_ir_functions=true \ --memory_address_verification=true \ diff --git a/src/cpu/codegen/function_generator.cc b/src/cpu/codegen/function_generator.cc index d4fb1f528..b3bb30e71 100644 --- a/src/cpu/codegen/function_generator.cc +++ b/src/cpu/codegen/function_generator.cc @@ -79,7 +79,7 @@ FunctionGenerator::FunctionGenerator( } if (FLAGS_log_codegen) { - printf("%s:\n", fn->name); + printf("%s:\n", fn->name()); } } @@ -394,10 +394,10 @@ BasicBlock* FunctionGenerator::GetReturnBasicBlock() { } Function* FunctionGenerator::GetFunction(FunctionSymbol* fn) { - Function* result = gen_module_->getFunction(StringRef(fn->name)); + Function* result = gen_module_->getFunction(StringRef(fn->name())); if (!result) { XELOGE(XT("Static function not found: %.8X %s"), - fn->start_address, fn->name); + fn->start_address, fn->name()); } XEASSERTNOTNULL(result); return result; diff --git a/src/cpu/codegen/module_generator.cc b/src/cpu/codegen/module_generator.cc index 77f11ed64..57b500add 100644 --- a/src/cpu/codegen/module_generator.cc +++ b/src/cpu/codegen/module_generator.cc @@ -191,7 +191,7 @@ void ModuleGenerator::AddMissingImport(FunctionSymbol* fn) { LLVMContext& context = m->getContext(); // Create the function (and setup args/attributes/etc). - Function* f = CreateFunctionDefinition(fn->name); + Function* f = CreateFunctionDefinition(fn->name()); BasicBlock* block = BasicBlock::Create(context, "entry", f); IRBuilder<> b(block); @@ -257,7 +257,7 @@ void ModuleGenerator::AddPresentImport(FunctionSymbol* fn) { (void*)fn->kernel_export->function_data.shim); // Create the function (and setup args/attributes/etc). - Function* f = CreateFunctionDefinition(fn->name); + Function* f = CreateFunctionDefinition(fn->name()); BasicBlock* block = BasicBlock::Create(context, "entry", f); IRBuilder<> b(block); @@ -287,7 +287,7 @@ void ModuleGenerator::PrepareFunction(FunctionSymbol* fn) { // LLVMContext& context = m->getContext(); // Create the function (and setup args/attributes/etc). - Function* f = CreateFunctionDefinition(fn->name); + Function* f = CreateFunctionDefinition(fn->name()); // Setup our codegen wrapper to keep all the pointers together. CodegenFunction* cgf = new CodegenFunction(); diff --git a/src/cpu/cpu-private.h b/src/cpu/cpu-private.h index ccf14ec29..d9966c5ec 100644 --- a/src/cpu/cpu-private.h +++ b/src/cpu/cpu-private.h @@ -17,6 +17,8 @@ DECLARE_bool(trace_instructions); DECLARE_bool(trace_user_calls); DECLARE_bool(trace_kernel_calls); +DECLARE_string(load_module_map); + DECLARE_string(dump_path); DECLARE_bool(dump_module_bitcode); DECLARE_bool(dump_module_map); diff --git a/src/cpu/cpu.cc b/src/cpu/cpu.cc index 5b316212d..6cad92513 100644 --- a/src/cpu/cpu.cc +++ b/src/cpu/cpu.cc @@ -10,9 +10,6 @@ #include "cpu/cpu-private.h" -// Debugging: - - // Tracing: DEFINE_bool(trace_instructions, false, "Trace all instructions."); @@ -22,6 +19,12 @@ DEFINE_bool(trace_kernel_calls, false, "Trace all kernel function calls."); +// Debugging: +DEFINE_string(load_module_map, "", + "Loads a .map for symbol names and to diff with the generated symbol " + "database."); + + // Dumping: DEFINE_string(dump_path, "build/", "Directory that dump files are placed into."); diff --git a/src/cpu/exec_module.cc b/src/cpu/exec_module.cc index 60c9b471a..514523dc8 100644 --- a/src/cpu/exec_module.cc +++ b/src/cpu/exec_module.cc @@ -136,11 +136,16 @@ int ExecModule::Prepare() { // Analyze the module and add its symbols to the symbol database. XEEXPECTZERO(sdb_->Analyze()); + // Load a specified module map and diff. + if (FLAGS_load_module_map.size()) { + sdb_->ReadMap(FLAGS_load_module_map.c_str()); + } + // Dump the symbol database. if (FLAGS_dump_module_map) { xesnprintfa(file_name, XECOUNT(file_name), "%s%s.map", FLAGS_dump_path.c_str(), module_name_); - sdb_->Write(file_name); + sdb_->WriteMap(file_name); } // Initialize the module. @@ -318,5 +323,5 @@ int ExecModule::Uninit() { } void ExecModule::Dump() { - sdb_->Dump(); + sdb_->Dump(stdout); } diff --git a/src/cpu/llvm_exports.cc b/src/cpu/llvm_exports.cc index bb32bcf15..a675e524b 100644 --- a/src/cpu/llvm_exports.cc +++ b/src/cpu/llvm_exports.cc @@ -81,7 +81,7 @@ void XeTraceKernelCall(xe_ppc_state_t* state, uint64_t cia, uint64_t call_ia, void XeTraceUserCall(xe_ppc_state_t* state, uint64_t cia, uint64_t call_ia, FunctionSymbol* fn) { XELOGCPU(XT("TRACE: %.8X -> u.%.8X (%s)"), - (uint32_t)call_ia - 4, (uint32_t)cia, fn->name); + (uint32_t)call_ia - 4, (uint32_t)cia, fn->name()); } void XeTraceInstruction(xe_ppc_state_t* state, uint32_t cia, uint32_t data) { diff --git a/src/cpu/processor.cc b/src/cpu/processor.cc index a1acd7981..cb2e6988d 100644 --- a/src/cpu/processor.cc +++ b/src/cpu/processor.cc @@ -175,8 +175,6 @@ int Processor::PrepareModule(const char* name, const char* path, exec_module->AddFunctionsToMap(all_fns_); modules_.push_back(exec_module); - exec_module->Dump(); - return 0; } diff --git a/src/cpu/sdb/symbol.cc b/src/cpu/sdb/symbol.cc index 7ac5257f3..c93972bd2 100644 --- a/src/cpu/sdb/symbol.cc +++ b/src/cpu/sdb/symbol.cc @@ -20,21 +20,47 @@ using namespace xe::cpu::sdb; using namespace xe::kernel; +Symbol::Symbol(SymbolType type) : + symbol_type(type), + name_(NULL) { +} + +Symbol::~Symbol() { + xe_free(name_); +} + +const char* Symbol::name() { + return name_; +} + +void Symbol::set_name(const char* value) { + if (name_ == value) { + return; + } + if (name_) { + xe_free(name_); + } + if (value) { + name_ = xestrdupa(value); + } +} + + FunctionBlock::FunctionBlock() : start_address(0), end_address(0), outgoing_type(kTargetUnknown), outgoing_address(0), outgoing_function(0) { } + FunctionSymbol::FunctionSymbol() : Symbol(Function), - start_address(0), end_address(0), name(0), + start_address(0), end_address(0), type(Unknown), flags(0), kernel_export(0), ee(0) { } FunctionSymbol::~FunctionSymbol() { - delete name; for (std::map::iterator it = blocks.begin(); it != blocks.end(); ++it) { delete it->second; @@ -79,16 +105,17 @@ FunctionBlock* FunctionSymbol::SplitBlock(uint32_t address) { return NULL; } + VariableSymbol::VariableSymbol() : Symbol(Variable), - address(0), name(0), + address(0), kernel_export(0) { } VariableSymbol::~VariableSymbol() { - delete name; } + ExceptionEntrySymbol::ExceptionEntrySymbol() : Symbol(ExceptionEntry), address(0), function(0) { diff --git a/src/cpu/sdb/symbol_database.cc b/src/cpu/sdb/symbol_database.cc index 6e3416028..976926a1c 100644 --- a/src/cpu/sdb/symbol_database.cc +++ b/src/cpu/sdb/symbol_database.cc @@ -9,6 +9,9 @@ #include +#include +#include + #include @@ -41,7 +44,7 @@ int SymbolDatabase::Analyze() { // Queue entry point of the application. FunctionSymbol* fn = GetOrInsertFunction(GetEntryPoint()); - fn->name = xestrdupa("start"); + fn->set_name("start"); // Keep pumping the queue until there's nothing left to do. FlushQueue(); @@ -79,6 +82,14 @@ int SymbolDatabase::Analyze() { return 0; } +Symbol* SymbolDatabase::GetSymbol(uint32_t address) { + SymbolMap::iterator i = symbols_.find(address); + if (i != symbols_.end()) { + return i->second; + } + return NULL; +} + ExceptionEntrySymbol* SymbolDatabase::GetOrInsertExceptionEntry( uint32_t address) { SymbolMap::iterator i = symbols_.find(address); @@ -159,81 +170,6 @@ int SymbolDatabase::GetAllFunctions(vector& functions) { return 0; } -void SymbolDatabase::Write(const char* file_name) { - // TODO(benvanik): write to file. -} - -void SymbolDatabase::Dump() { - uint32_t previous = 0; - for (SymbolMap::iterator it = symbols_.begin(); it != symbols_.end(); ++it) { - switch (it->second->symbol_type) { - case Symbol::Function: - { - FunctionSymbol* fn = static_cast(it->second); - if (previous && (int)(fn->start_address - previous) > 0) { - if (fn->start_address - previous > 4 || - *((uint32_t*)xe_memory_addr(memory_, previous)) != 0) { - printf("%.8X-%.8X (%5d) h\n", previous, fn->start_address, - fn->start_address - previous); - } - } - printf("%.8X-%.8X (%5d) f %s\n", fn->start_address, - fn->end_address + 4, - fn->end_address - fn->start_address + 4, - fn->name ? fn->name : ""); - previous = fn->end_address + 4; - DumpFunctionBlocks(fn); - } - break; - case Symbol::Variable: - { - VariableSymbol* var = static_cast(it->second); - printf("%.8X v %s\n", var->address, - var->name ? var->name : ""); - } - break; - case Symbol::ExceptionEntry: - { - ExceptionEntrySymbol* ee = static_cast( - it->second); - printf("%.8X-%.8X (%5d) e of %.8X\n", - ee->address, ee->address + 8, 8, - ee->function ? ee->function->start_address : 0); - previous = ee->address + 8 + 4; - } - break; - } - } -} - -void SymbolDatabase::DumpFunctionBlocks(FunctionSymbol* fn) { - for (std::map::iterator it = fn->blocks.begin(); - it != fn->blocks.end(); ++it) { - FunctionBlock* block = it->second; - printf(" bb %.8X-%.8X", block->start_address, block->end_address + 4); - switch (block->outgoing_type) { - case FunctionBlock::kTargetUnknown: - printf(" ?\n"); - break; - case FunctionBlock::kTargetBlock: - printf(" branch %.8X\n", block->outgoing_block->start_address); - break; - case FunctionBlock::kTargetFunction: - printf(" call %.8X %s\n", block->outgoing_function->start_address, block->outgoing_function->name); - break; - case FunctionBlock::kTargetLR: - printf(" branch lr\n"); - break; - case FunctionBlock::kTargetCTR: - printf(" branch ctr\n"); - break; - case FunctionBlock::kTargetNone: - printf("\n"); - break; - } - } -} - int SymbolDatabase::AnalyzeFunction(FunctionSymbol* fn) { // Ignore functions already analyzed. if (fn->blocks.size()) { @@ -299,10 +235,10 @@ int SymbolDatabase::AnalyzeFunction(FunctionSymbol* fn) { XELOGSDB(XT("Analyzing function %.8X..."), fn->start_address); // Set a default name, if it hasn't been named already. - if (!fn->name) { + if (!fn->name()) { char name[32]; xesnprintfa(name, XECOUNT(name), "sub_%.8X", fn->start_address); - fn->name = xestrdupa(name); + fn->set_name(name); } // Set type, if needed. We assume user if not set. @@ -622,11 +558,11 @@ bool SymbolDatabase::FillHoles() { VariableSymbol* var = GetOrInsertVariable(data_addr); char name[128]; if (ee->function) { - xesnprintfa(name, XECOUNT(name), "__ee_data_%s", ee->function->name); + xesnprintfa(name, XECOUNT(name), "__ee_data_%s", ee->function->name()); } else { xesnprintfa(name, XECOUNT(name), "__ee_data_%.8X", *it); } - var->name = xestrdupa(name); + var->set_name(name); } } @@ -659,3 +595,154 @@ bool SymbolDatabase::IsRestGprLr(uint32_t addr) { FunctionSymbol* fn = GetFunction(addr); return fn && (fn->flags & FunctionSymbol::kFlagRestGprLr); } + +void SymbolDatabase::ReadMap(const char* file_name) { + std::ifstream infile(file_name); + + // Skip until ' Address'. Skip the next blank line. + std::string line; + while (std::getline(infile, line)) { + if (line.find(" Address") == 0) { + // Skip the next line. + std::getline(infile, line); + break; + } + } + + std::stringstream sstream; + std::string ignore; + std::string name; + std::string addr_str; + std::string type_str; + while (std::getline(infile, line)) { + // Remove newline. + while (line.size() && + (line[line.size() - 1] == '\r' || + line[line.size() - 1] == '\n')) { + line.erase(line.end() - 1); + } + + // End when we hit the first whitespace. + if (line.size() == 0) { + break; + } + + // Line is [ws][ignore][ws][name][ws][hex addr][ws][(f)][ws][library] + sstream.clear(); + sstream.str(line); + sstream >> std::ws; + sstream >> ignore; + sstream >> std::ws; + sstream >> name; + sstream >> std::ws; + sstream >> addr_str; + sstream >> std::ws; + sstream >> type_str; + + uint32_t addr = (uint32_t)strtol(addr_str.c_str(), NULL, 16); + if (!addr) { + continue; + } + + Symbol* symbol = GetSymbol(addr); + if (symbol) { + // Symbol found - set name. + // We could check the type, but it's not needed. + symbol->set_name(name.c_str()); + } else { + if (type_str == "f") { + // Function was not found via analysis. + // We don't want to add it here as that would make us require maps to + // get working. + XELOGSDB(XT("MAP DIFF: function %.8X %s not found during analysis"), + addr, name.c_str()); + } else { + // Add a new variable. + // This is just helpful, but changes no behavior. + VariableSymbol* var = GetOrInsertVariable(addr); + var->set_name(name.c_str()); + } + } + } +} + +void SymbolDatabase::WriteMap(const char* file_name) { + FILE* file = fopen(file_name, "wt"); + Dump(file); + fclose(file); +} + +void SymbolDatabase::Dump(FILE* file) { + uint32_t previous = 0; + for (SymbolMap::iterator it = symbols_.begin(); it != symbols_.end(); ++it) { + switch (it->second->symbol_type) { + case Symbol::Function: + { + FunctionSymbol* fn = static_cast(it->second); + if (previous && (int)(fn->start_address - previous) > 0) { + if (fn->start_address - previous > 4 || + *((uint32_t*)xe_memory_addr(memory_, previous)) != 0) { + fprintf(file, "%.8X-%.8X (%5d) h\n", previous, fn->start_address, + fn->start_address - previous); + } + } + fprintf(file, "%.8X-%.8X (%5d) f %s\n", + fn->start_address, + fn->end_address + 4, + fn->end_address - fn->start_address + 4, + fn->name() ? fn->name() : ""); + previous = fn->end_address + 4; + DumpFunctionBlocks(file, fn); + } + break; + case Symbol::Variable: + { + VariableSymbol* var = static_cast(it->second); + fprintf(file, "%.8X v %s\n", var->address, + var->name() ? var->name() : ""); + } + break; + case Symbol::ExceptionEntry: + { + ExceptionEntrySymbol* ee = static_cast( + it->second); + fprintf(file, "%.8X-%.8X (%5d) e of %.8X\n", + ee->address, ee->address + 8, 8, + ee->function ? ee->function->start_address : 0); + previous = ee->address + 8 + 4; + } + break; + } + } +} + +void SymbolDatabase::DumpFunctionBlocks(FILE* file, FunctionSymbol* fn) { + for (std::map::iterator it = fn->blocks.begin(); + it != fn->blocks.end(); ++it) { + FunctionBlock* block = it->second; + fprintf(file, " bb %.8X-%.8X", + block->start_address, block->end_address + 4); + switch (block->outgoing_type) { + case FunctionBlock::kTargetUnknown: + fprintf(file, " ?\n"); + break; + case FunctionBlock::kTargetBlock: + fprintf(file, " branch %.8X\n", block->outgoing_block->start_address); + break; + case FunctionBlock::kTargetFunction: + fprintf(file, " call %.8X %s\n", + block->outgoing_function->start_address, + block->outgoing_function->name()); + break; + case FunctionBlock::kTargetLR: + fprintf(file, " branch lr\n"); + break; + case FunctionBlock::kTargetCTR: + fprintf(file, " branch ctr\n"); + break; + case FunctionBlock::kTargetNone: + fprintf(file, "\n"); + break; + } + } +} diff --git a/src/cpu/sdb/xex_symbol_database.cc b/src/cpu/sdb/xex_symbol_database.cc index c1b28eeef..40877dfb9 100644 --- a/src/cpu/sdb/xex_symbol_database.cc +++ b/src/cpu/sdb/xex_symbol_database.cc @@ -163,7 +163,7 @@ int XexSymbolDatabase::FindGplr() { xesnprintfa(name, XECOUNT(name), "__savegprlr_%d", n); FunctionSymbol* fn = GetOrInsertFunction(address); fn->end_address = fn->start_address + (31 - n) * 4 + 2 * 4; - fn->name = xestrdupa(name); + fn->set_name(name); fn->type = FunctionSymbol::User; fn->flags |= FunctionSymbol::kFlagSaveGprLr; address += 4; @@ -173,7 +173,7 @@ int XexSymbolDatabase::FindGplr() { xesnprintfa(name, XECOUNT(name), "__restgprlr_%d", n); FunctionSymbol* fn = GetOrInsertFunction(address); fn->end_address = fn->start_address + (31 - n) * 4 + 3 * 4; - fn->name = xestrdupa(name); + fn->set_name(name); fn->type = FunctionSymbol::User; fn->flags |= FunctionSymbol::kFlagRestGprLr; address += 4; @@ -208,7 +208,7 @@ int XexSymbolDatabase::AddImports(const xe_xex2_import_library_t* library) { xesnprintfa(name, XECOUNT(name), "__imp__%s_%.3X", library->name, info->ordinal); } - var->name = xestrdupa(name); + var->set_name(name); var->kernel_export = kernel_export; if (info->thunk_address) { FunctionSymbol* fn = GetOrInsertFunction(info->thunk_address); @@ -221,7 +221,7 @@ int XexSymbolDatabase::AddImports(const xe_xex2_import_library_t* library) { xesnprintfa(name, XECOUNT(name), "__kernel_%s_%.3X", library->name, info->ordinal); } - fn->name = xestrdupa(name); + fn->set_name(name); } }