Read and write map files.
This commit is contained in:
parent
a020072ed7
commit
59ccfdd999
|
@ -49,12 +49,17 @@ public:
|
||||||
ExceptionEntry = 2,
|
ExceptionEntry = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual ~Symbol() {}
|
virtual ~Symbol();
|
||||||
|
|
||||||
SymbolType symbol_type;
|
SymbolType symbol_type;
|
||||||
|
|
||||||
|
const char* name();
|
||||||
|
void set_name(const char* value);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Symbol(SymbolType type) : symbol_type(type) {}
|
Symbol(SymbolType type);
|
||||||
|
|
||||||
|
char* name_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ExceptionEntrySymbol;
|
class ExceptionEntrySymbol;
|
||||||
|
@ -105,7 +110,6 @@ public:
|
||||||
|
|
||||||
uint32_t start_address;
|
uint32_t start_address;
|
||||||
uint32_t end_address;
|
uint32_t end_address;
|
||||||
char* name;
|
|
||||||
FunctionType type;
|
FunctionType type;
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
|
|
||||||
|
@ -125,7 +129,6 @@ public:
|
||||||
virtual ~VariableSymbol();
|
virtual ~VariableSymbol();
|
||||||
|
|
||||||
uint32_t address;
|
uint32_t address;
|
||||||
char* name;
|
|
||||||
|
|
||||||
kernel::KernelExport* kernel_export;
|
kernel::KernelExport* kernel_export;
|
||||||
};
|
};
|
||||||
|
|
|
@ -32,22 +32,23 @@ public:
|
||||||
|
|
||||||
virtual int Analyze();
|
virtual int Analyze();
|
||||||
|
|
||||||
|
Symbol* GetSymbol(uint32_t address);
|
||||||
ExceptionEntrySymbol* GetOrInsertExceptionEntry(uint32_t address);
|
ExceptionEntrySymbol* GetOrInsertExceptionEntry(uint32_t address);
|
||||||
FunctionSymbol* GetOrInsertFunction(uint32_t address);
|
FunctionSymbol* GetOrInsertFunction(uint32_t address);
|
||||||
VariableSymbol* GetOrInsertVariable(uint32_t address);
|
VariableSymbol* GetOrInsertVariable(uint32_t address);
|
||||||
FunctionSymbol* GetFunction(uint32_t address);
|
FunctionSymbol* GetFunction(uint32_t address);
|
||||||
VariableSymbol* GetVariable(uint32_t address);
|
VariableSymbol* GetVariable(uint32_t address);
|
||||||
Symbol* GetSymbol(uint32_t address);
|
|
||||||
|
|
||||||
int GetAllVariables(std::vector<VariableSymbol*>& variables);
|
int GetAllVariables(std::vector<VariableSymbol*>& variables);
|
||||||
int GetAllFunctions(std::vector<FunctionSymbol*>& functions);
|
int GetAllFunctions(std::vector<FunctionSymbol*>& functions);
|
||||||
|
|
||||||
void Write(const char* file_name);
|
void ReadMap(const char* file_name);
|
||||||
void Dump();
|
void WriteMap(const char* file_name);
|
||||||
void DumpFunctionBlocks(FunctionSymbol* fn);
|
void Dump(FILE* file);
|
||||||
|
void DumpFunctionBlocks(FILE* file, FunctionSymbol* fn);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
typedef std::tr1::unordered_map<uint32_t, Symbol*> SymbolMap;
|
typedef std::map<uint32_t, Symbol*> SymbolMap;
|
||||||
typedef std::list<FunctionSymbol*> FunctionList;
|
typedef std::list<FunctionSymbol*> FunctionList;
|
||||||
|
|
||||||
int AnalyzeFunction(FunctionSymbol* fn);
|
int AnalyzeFunction(FunctionSymbol* fn);
|
||||||
|
|
|
@ -8,6 +8,9 @@ fi
|
||||||
|
|
||||||
./build/xenia/release/xenia-run \
|
./build/xenia/release/xenia-run \
|
||||||
private/$1 \
|
private/$1 \
|
||||||
|
--dump_path=build/ \
|
||||||
|
--dump_module_map=true \
|
||||||
|
--dump_module_bitcode=true \
|
||||||
--optimize_ir_modules=true \
|
--optimize_ir_modules=true \
|
||||||
--optimize_ir_functions=true \
|
--optimize_ir_functions=true \
|
||||||
--memory_address_verification=true \
|
--memory_address_verification=true \
|
||||||
|
|
|
@ -79,7 +79,7 @@ FunctionGenerator::FunctionGenerator(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FLAGS_log_codegen) {
|
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* FunctionGenerator::GetFunction(FunctionSymbol* fn) {
|
||||||
Function* result = gen_module_->getFunction(StringRef(fn->name));
|
Function* result = gen_module_->getFunction(StringRef(fn->name()));
|
||||||
if (!result) {
|
if (!result) {
|
||||||
XELOGE(XT("Static function not found: %.8X %s"),
|
XELOGE(XT("Static function not found: %.8X %s"),
|
||||||
fn->start_address, fn->name);
|
fn->start_address, fn->name());
|
||||||
}
|
}
|
||||||
XEASSERTNOTNULL(result);
|
XEASSERTNOTNULL(result);
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -191,7 +191,7 @@ void ModuleGenerator::AddMissingImport(FunctionSymbol* fn) {
|
||||||
LLVMContext& context = m->getContext();
|
LLVMContext& context = m->getContext();
|
||||||
|
|
||||||
// Create the function (and setup args/attributes/etc).
|
// 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);
|
BasicBlock* block = BasicBlock::Create(context, "entry", f);
|
||||||
IRBuilder<> b(block);
|
IRBuilder<> b(block);
|
||||||
|
@ -257,7 +257,7 @@ void ModuleGenerator::AddPresentImport(FunctionSymbol* fn) {
|
||||||
(void*)fn->kernel_export->function_data.shim);
|
(void*)fn->kernel_export->function_data.shim);
|
||||||
|
|
||||||
// Create the function (and setup args/attributes/etc).
|
// 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);
|
BasicBlock* block = BasicBlock::Create(context, "entry", f);
|
||||||
IRBuilder<> b(block);
|
IRBuilder<> b(block);
|
||||||
|
@ -287,7 +287,7 @@ void ModuleGenerator::PrepareFunction(FunctionSymbol* fn) {
|
||||||
// LLVMContext& context = m->getContext();
|
// LLVMContext& context = m->getContext();
|
||||||
|
|
||||||
// Create the function (and setup args/attributes/etc).
|
// 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.
|
// Setup our codegen wrapper to keep all the pointers together.
|
||||||
CodegenFunction* cgf = new CodegenFunction();
|
CodegenFunction* cgf = new CodegenFunction();
|
||||||
|
|
|
@ -17,6 +17,8 @@ DECLARE_bool(trace_instructions);
|
||||||
DECLARE_bool(trace_user_calls);
|
DECLARE_bool(trace_user_calls);
|
||||||
DECLARE_bool(trace_kernel_calls);
|
DECLARE_bool(trace_kernel_calls);
|
||||||
|
|
||||||
|
DECLARE_string(load_module_map);
|
||||||
|
|
||||||
DECLARE_string(dump_path);
|
DECLARE_string(dump_path);
|
||||||
DECLARE_bool(dump_module_bitcode);
|
DECLARE_bool(dump_module_bitcode);
|
||||||
DECLARE_bool(dump_module_map);
|
DECLARE_bool(dump_module_map);
|
||||||
|
|
|
@ -10,9 +10,6 @@
|
||||||
#include "cpu/cpu-private.h"
|
#include "cpu/cpu-private.h"
|
||||||
|
|
||||||
|
|
||||||
// Debugging:
|
|
||||||
|
|
||||||
|
|
||||||
// Tracing:
|
// Tracing:
|
||||||
DEFINE_bool(trace_instructions, false,
|
DEFINE_bool(trace_instructions, false,
|
||||||
"Trace all instructions.");
|
"Trace all instructions.");
|
||||||
|
@ -22,6 +19,12 @@ DEFINE_bool(trace_kernel_calls, false,
|
||||||
"Trace all kernel function calls.");
|
"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:
|
// Dumping:
|
||||||
DEFINE_string(dump_path, "build/",
|
DEFINE_string(dump_path, "build/",
|
||||||
"Directory that dump files are placed into.");
|
"Directory that dump files are placed into.");
|
||||||
|
|
|
@ -136,11 +136,16 @@ int ExecModule::Prepare() {
|
||||||
// Analyze the module and add its symbols to the symbol database.
|
// Analyze the module and add its symbols to the symbol database.
|
||||||
XEEXPECTZERO(sdb_->Analyze());
|
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.
|
// Dump the symbol database.
|
||||||
if (FLAGS_dump_module_map) {
|
if (FLAGS_dump_module_map) {
|
||||||
xesnprintfa(file_name, XECOUNT(file_name),
|
xesnprintfa(file_name, XECOUNT(file_name),
|
||||||
"%s%s.map", FLAGS_dump_path.c_str(), module_name_);
|
"%s%s.map", FLAGS_dump_path.c_str(), module_name_);
|
||||||
sdb_->Write(file_name);
|
sdb_->WriteMap(file_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the module.
|
// Initialize the module.
|
||||||
|
@ -318,5 +323,5 @@ int ExecModule::Uninit() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExecModule::Dump() {
|
void ExecModule::Dump() {
|
||||||
sdb_->Dump();
|
sdb_->Dump(stdout);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
void XeTraceUserCall(xe_ppc_state_t* state, uint64_t cia, uint64_t call_ia,
|
||||||
FunctionSymbol* fn) {
|
FunctionSymbol* fn) {
|
||||||
XELOGCPU(XT("TRACE: %.8X -> u.%.8X (%s)"),
|
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) {
|
void XeTraceInstruction(xe_ppc_state_t* state, uint32_t cia, uint32_t data) {
|
||||||
|
|
|
@ -175,8 +175,6 @@ int Processor::PrepareModule(const char* name, const char* path,
|
||||||
exec_module->AddFunctionsToMap(all_fns_);
|
exec_module->AddFunctionsToMap(all_fns_);
|
||||||
modules_.push_back(exec_module);
|
modules_.push_back(exec_module);
|
||||||
|
|
||||||
exec_module->Dump();
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,21 +20,47 @@ using namespace xe::cpu::sdb;
|
||||||
using namespace xe::kernel;
|
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() :
|
FunctionBlock::FunctionBlock() :
|
||||||
start_address(0), end_address(0),
|
start_address(0), end_address(0),
|
||||||
outgoing_type(kTargetUnknown), outgoing_address(0),
|
outgoing_type(kTargetUnknown), outgoing_address(0),
|
||||||
outgoing_function(0) {
|
outgoing_function(0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
FunctionSymbol::FunctionSymbol() :
|
FunctionSymbol::FunctionSymbol() :
|
||||||
Symbol(Function),
|
Symbol(Function),
|
||||||
start_address(0), end_address(0), name(0),
|
start_address(0), end_address(0),
|
||||||
type(Unknown), flags(0),
|
type(Unknown), flags(0),
|
||||||
kernel_export(0), ee(0) {
|
kernel_export(0), ee(0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionSymbol::~FunctionSymbol() {
|
FunctionSymbol::~FunctionSymbol() {
|
||||||
delete name;
|
|
||||||
for (std::map<uint32_t, FunctionBlock*>::iterator it = blocks.begin();
|
for (std::map<uint32_t, FunctionBlock*>::iterator it = blocks.begin();
|
||||||
it != blocks.end(); ++it) {
|
it != blocks.end(); ++it) {
|
||||||
delete it->second;
|
delete it->second;
|
||||||
|
@ -79,16 +105,17 @@ FunctionBlock* FunctionSymbol::SplitBlock(uint32_t address) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
VariableSymbol::VariableSymbol() :
|
VariableSymbol::VariableSymbol() :
|
||||||
Symbol(Variable),
|
Symbol(Variable),
|
||||||
address(0), name(0),
|
address(0),
|
||||||
kernel_export(0) {
|
kernel_export(0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
VariableSymbol::~VariableSymbol() {
|
VariableSymbol::~VariableSymbol() {
|
||||||
delete name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ExceptionEntrySymbol::ExceptionEntrySymbol() :
|
ExceptionEntrySymbol::ExceptionEntrySymbol() :
|
||||||
Symbol(ExceptionEntry),
|
Symbol(ExceptionEntry),
|
||||||
address(0), function(0) {
|
address(0), function(0) {
|
||||||
|
|
|
@ -9,6 +9,9 @@
|
||||||
|
|
||||||
#include <xenia/cpu/sdb/symbol_database.h>
|
#include <xenia/cpu/sdb/symbol_database.h>
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
#include <xenia/cpu/ppc/instr.h>
|
#include <xenia/cpu/ppc/instr.h>
|
||||||
|
|
||||||
|
|
||||||
|
@ -41,7 +44,7 @@ int SymbolDatabase::Analyze() {
|
||||||
|
|
||||||
// Queue entry point of the application.
|
// Queue entry point of the application.
|
||||||
FunctionSymbol* fn = GetOrInsertFunction(GetEntryPoint());
|
FunctionSymbol* fn = GetOrInsertFunction(GetEntryPoint());
|
||||||
fn->name = xestrdupa("start");
|
fn->set_name("start");
|
||||||
|
|
||||||
// Keep pumping the queue until there's nothing left to do.
|
// Keep pumping the queue until there's nothing left to do.
|
||||||
FlushQueue();
|
FlushQueue();
|
||||||
|
@ -79,6 +82,14 @@ int SymbolDatabase::Analyze() {
|
||||||
return 0;
|
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(
|
ExceptionEntrySymbol* SymbolDatabase::GetOrInsertExceptionEntry(
|
||||||
uint32_t address) {
|
uint32_t address) {
|
||||||
SymbolMap::iterator i = symbols_.find(address);
|
SymbolMap::iterator i = symbols_.find(address);
|
||||||
|
@ -159,81 +170,6 @@ int SymbolDatabase::GetAllFunctions(vector<FunctionSymbol*>& functions) {
|
||||||
return 0;
|
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<FunctionSymbol*>(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 : "<unknown>");
|
|
||||||
previous = fn->end_address + 4;
|
|
||||||
DumpFunctionBlocks(fn);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Symbol::Variable:
|
|
||||||
{
|
|
||||||
VariableSymbol* var = static_cast<VariableSymbol*>(it->second);
|
|
||||||
printf("%.8X v %s\n", var->address,
|
|
||||||
var->name ? var->name : "<unknown>");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Symbol::ExceptionEntry:
|
|
||||||
{
|
|
||||||
ExceptionEntrySymbol* ee = static_cast<ExceptionEntrySymbol*>(
|
|
||||||
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<uint32_t, FunctionBlock*>::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) {
|
int SymbolDatabase::AnalyzeFunction(FunctionSymbol* fn) {
|
||||||
// Ignore functions already analyzed.
|
// Ignore functions already analyzed.
|
||||||
if (fn->blocks.size()) {
|
if (fn->blocks.size()) {
|
||||||
|
@ -299,10 +235,10 @@ int SymbolDatabase::AnalyzeFunction(FunctionSymbol* fn) {
|
||||||
XELOGSDB(XT("Analyzing function %.8X..."), fn->start_address);
|
XELOGSDB(XT("Analyzing function %.8X..."), fn->start_address);
|
||||||
|
|
||||||
// Set a default name, if it hasn't been named already.
|
// Set a default name, if it hasn't been named already.
|
||||||
if (!fn->name) {
|
if (!fn->name()) {
|
||||||
char name[32];
|
char name[32];
|
||||||
xesnprintfa(name, XECOUNT(name), "sub_%.8X", fn->start_address);
|
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.
|
// Set type, if needed. We assume user if not set.
|
||||||
|
@ -622,11 +558,11 @@ bool SymbolDatabase::FillHoles() {
|
||||||
VariableSymbol* var = GetOrInsertVariable(data_addr);
|
VariableSymbol* var = GetOrInsertVariable(data_addr);
|
||||||
char name[128];
|
char name[128];
|
||||||
if (ee->function) {
|
if (ee->function) {
|
||||||
xesnprintfa(name, XECOUNT(name), "__ee_data_%s", ee->function->name);
|
xesnprintfa(name, XECOUNT(name), "__ee_data_%s", ee->function->name());
|
||||||
} else {
|
} else {
|
||||||
xesnprintfa(name, XECOUNT(name), "__ee_data_%.8X", *it);
|
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);
|
FunctionSymbol* fn = GetFunction(addr);
|
||||||
return fn && (fn->flags & FunctionSymbol::kFlagRestGprLr);
|
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<FunctionSymbol*>(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() : "<unknown>");
|
||||||
|
previous = fn->end_address + 4;
|
||||||
|
DumpFunctionBlocks(file, fn);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Symbol::Variable:
|
||||||
|
{
|
||||||
|
VariableSymbol* var = static_cast<VariableSymbol*>(it->second);
|
||||||
|
fprintf(file, "%.8X v %s\n", var->address,
|
||||||
|
var->name() ? var->name() : "<unknown>");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Symbol::ExceptionEntry:
|
||||||
|
{
|
||||||
|
ExceptionEntrySymbol* ee = static_cast<ExceptionEntrySymbol*>(
|
||||||
|
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<uint32_t, FunctionBlock*>::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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -163,7 +163,7 @@ int XexSymbolDatabase::FindGplr() {
|
||||||
xesnprintfa(name, XECOUNT(name), "__savegprlr_%d", n);
|
xesnprintfa(name, XECOUNT(name), "__savegprlr_%d", n);
|
||||||
FunctionSymbol* fn = GetOrInsertFunction(address);
|
FunctionSymbol* fn = GetOrInsertFunction(address);
|
||||||
fn->end_address = fn->start_address + (31 - n) * 4 + 2 * 4;
|
fn->end_address = fn->start_address + (31 - n) * 4 + 2 * 4;
|
||||||
fn->name = xestrdupa(name);
|
fn->set_name(name);
|
||||||
fn->type = FunctionSymbol::User;
|
fn->type = FunctionSymbol::User;
|
||||||
fn->flags |= FunctionSymbol::kFlagSaveGprLr;
|
fn->flags |= FunctionSymbol::kFlagSaveGprLr;
|
||||||
address += 4;
|
address += 4;
|
||||||
|
@ -173,7 +173,7 @@ int XexSymbolDatabase::FindGplr() {
|
||||||
xesnprintfa(name, XECOUNT(name), "__restgprlr_%d", n);
|
xesnprintfa(name, XECOUNT(name), "__restgprlr_%d", n);
|
||||||
FunctionSymbol* fn = GetOrInsertFunction(address);
|
FunctionSymbol* fn = GetOrInsertFunction(address);
|
||||||
fn->end_address = fn->start_address + (31 - n) * 4 + 3 * 4;
|
fn->end_address = fn->start_address + (31 - n) * 4 + 3 * 4;
|
||||||
fn->name = xestrdupa(name);
|
fn->set_name(name);
|
||||||
fn->type = FunctionSymbol::User;
|
fn->type = FunctionSymbol::User;
|
||||||
fn->flags |= FunctionSymbol::kFlagRestGprLr;
|
fn->flags |= FunctionSymbol::kFlagRestGprLr;
|
||||||
address += 4;
|
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,
|
xesnprintfa(name, XECOUNT(name), "__imp__%s_%.3X", library->name,
|
||||||
info->ordinal);
|
info->ordinal);
|
||||||
}
|
}
|
||||||
var->name = xestrdupa(name);
|
var->set_name(name);
|
||||||
var->kernel_export = kernel_export;
|
var->kernel_export = kernel_export;
|
||||||
if (info->thunk_address) {
|
if (info->thunk_address) {
|
||||||
FunctionSymbol* fn = GetOrInsertFunction(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,
|
xesnprintfa(name, XECOUNT(name), "__kernel_%s_%.3X", library->name,
|
||||||
info->ordinal);
|
info->ordinal);
|
||||||
}
|
}
|
||||||
fn->name = xestrdupa(name);
|
fn->set_name(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue