Adding tracing methods.

This commit is contained in:
Ben Vanik 2013-01-24 00:10:24 -08:00
parent 385a4ee23b
commit 47481fecf7
8 changed files with 107 additions and 14 deletions

15
TODO.md
View File

@ -43,8 +43,6 @@ indicate expected values.
## Codegen
Make membase/state constant. Ensure optimized code uses constant value.
### Branch generation
Change style to match: http://llvm.org/docs/tutorial/LangImpl5.html
@ -85,16 +83,9 @@ OurFPM.add(createReassociatePass());
### Tracing
Tracing modes:
- off (0)
- syscalls (1)
- fn calls (2)
- all instructions (3)
Inject extern functions into module:
- XeTraceKernelCall(caller_ia, cia, name, state)
- XeTraceUserCall(caller_ia, cia, name, state)
- XeTraceInstruction(cia, state)
- Trace kernel export info (missing/present/etc).
- Trace user call info (name/?).
- Trace instruction info (disasm).
### Calling convention

View File

@ -136,6 +136,10 @@ typedef struct XECACHEALIGN64 xe_ppc_state {
// void set_fprf(const uint32_t v) {
// fpscr.value = (fpscr.value & ~0x000F8000) | v;
// }
// Runtime-specific data pointer. Used on callbacks to get access to the
// current runtime and its data.
void* runtime_data;
} xe_ppc_state_t;

View File

@ -5,8 +5,11 @@ rm build/$1*
./build/xenia/release/xenia-run \
private/$1 \
--optimize_ir_modules=false \
--optimize_ir_modules=true \
--optimize_ir_functions=false \
--trace_kernel_calls=true \
--trace_user_calls=true \
--trace_instructions=false \
2>build/run.llvm.txt 1>build/run.txt
if [ ! -s build/run.llvm.txt ]; then

View File

@ -11,6 +11,8 @@
#include <xenia/cpu/ppc/state.h>
#include "cpu/cpu-private.h"
using namespace llvm;
using namespace xe::cpu::codegen;
@ -82,10 +84,19 @@ FunctionBlock* FunctionGenerator::fn_block() {
void FunctionGenerator::GenerateBasicBlocks() {
// Always add an entry block.
BasicBlock* entry = BasicBlock::Create(*context_, "entry", gen_fn_);
builder_->SetInsertPoint(entry);
if (FLAGS_trace_user_calls) {
Value* traceUserCall = gen_module_->getGlobalVariable("XeTraceUserCall");
builder_->CreateCall3(
traceUserCall,
gen_fn_->arg_begin(),
builder_->getInt32(fn_->start_address),
builder_->getInt32(0));
}
// If this function is empty, abort!
if (!fn_->blocks.size()) {
builder_->SetInsertPoint(entry);
builder_->CreateRetVoid();
return;
}
@ -124,6 +135,9 @@ void FunctionGenerator::GenerateBasicBlock(FunctionBlock* block,
builder_->SetInsertPoint(bb);
//i->setMetadata("some.name", MDNode::get(context, MDString::get(context, pname)));
Value* traceInstruction =
gen_module_->getGlobalVariable("XeTraceInstruction");
// Walk instructions in block.
uint8_t* p = xe_memory_addr(memory_, 0);
for (uint32_t ia = block->start_address; ia <= block->end_address; ia += 4) {
@ -131,6 +145,15 @@ void FunctionGenerator::GenerateBasicBlock(FunctionBlock* block,
i.address = ia;
i.code = XEGETUINT32BE(p + ia);
i.type = ppc::GetInstrType(i.code);
if (FLAGS_trace_instructions) {
builder_->CreateCall3(
traceInstruction,
gen_fn_->arg_begin(),
builder_->getInt32(i.address),
builder_->getInt32(i.code));
}
if (!i.type) {
XELOGCPU("Invalid instruction at %.8X: %.8X\n", ia, i.code);
continue;

View File

@ -177,6 +177,16 @@ void ModuleGenerator::AddMissingImport(FunctionSymbol* fn) {
// TODO(benvanik): log errors.
BasicBlock* block = BasicBlock::Create(context, "entry", f);
IRBuilder<> builder(block);
if (FLAGS_trace_kernel_calls) {
Value* traceKernelCall = m->getGlobalVariable("XeTraceKernelCall");
builder.CreateCall3(
traceKernelCall,
f->arg_begin(),
builder.getInt32(fn->start_address),
builder.getInt32(0));
}
builder.CreateRetVoid();
OptimizeFunction(m, f);

View File

@ -13,6 +13,10 @@
#include <gflags/gflags.h>
DECLARE_bool(trace_instructions);
DECLARE_bool(trace_user_calls);
DECLARE_bool(trace_kernel_calls);
DECLARE_string(dump_path);
DECLARE_bool(dump_module_bitcode);
DECLARE_bool(dump_module_map);

View File

@ -13,6 +13,15 @@
// Debugging:
// Tracing:
DEFINE_bool(trace_instructions, false,
"Trace all instructions.");
DEFINE_bool(trace_user_calls, false,
"Trace all user function calls.");
DEFINE_bool(trace_kernel_calls, false,
"Trace all kernel function calls.");
// Dumping:
DEFINE_string(dump_path, "build/",
"Directory that dump files are placed into.");

View File

@ -30,6 +30,8 @@
#include <xenia/cpu/codegen/module_generator.h>
#include <xenia/cpu/sdb.h>
#include <xenia/cpu/ppc/instr.h>
#include <xenia/cpu/ppc/state.h>
#include "cpu/cpu-private.h"
#include "cpu/xethunk/xethunk.h"
@ -200,6 +202,26 @@ XECLEANUP:
return result_code;
}
void XeTraceKernelCall(xe_ppc_state_t* state, uint32_t cia, uint32_t call_ia) {
// TODO(benvanik): get names
XELOGCPU("TRACE: %.8X -> k.%.8X", call_ia, cia);
}
void XeTraceUserCall(xe_ppc_state_t* state, uint32_t cia, uint32_t call_ia) {
// TODO(benvanik): get names
XELOGCPU("TRACE: %.8X -> u.%.8X", call_ia, cia);
}
void XeTraceInstruction(xe_ppc_state_t* state, uint32_t cia, uint32_t data) {
ppc::InstrType* type = ppc::GetInstrType(data);
XELOGCPU("TRACE: %.8X %.8X %s %s",
cia, data,
type && type->emit ? " " : "X",
type ? type->name : "<unknown>");
// TODO(benvanik): better disassembly, printing of current register values/etc
}
int ExecModule::InjectGlobals() {
LLVMContext& context = *context_.get();
const DataLayout* dl = engine_->getDataLayout();
@ -222,6 +244,33 @@ int ExecModule::InjectGlobals() {
ConstantInt::get(intPtrTy, (uintptr_t)xe_memory_addr(memory_, 0)),
int8PtrTy));
// Tracing methods:
std::vector<Type*> traceCallArgs;
traceCallArgs.push_back(int8PtrTy);
traceCallArgs.push_back(Type::getInt32Ty(context));
traceCallArgs.push_back(Type::getInt32Ty(context));
FunctionType* traceCallTy = FunctionType::get(
Type::getVoidTy(context), traceCallArgs, false);
std::vector<Type*> traceInstructionArgs;
traceInstructionArgs.push_back(int8PtrTy);
traceInstructionArgs.push_back(Type::getInt32Ty(context));
traceInstructionArgs.push_back(Type::getInt32Ty(context));
FunctionType* traceInstructionTy = FunctionType::get(
Type::getVoidTy(context), traceInstructionArgs, false);
gv = new GlobalVariable(*gen_module_, traceCallTy, true,
GlobalValue::ExternalLinkage, 0,
"XeTraceKernelCall");
engine_->addGlobalMapping(gv, (void*)&XeTraceKernelCall);
gv = new GlobalVariable(*gen_module_, traceCallTy, true,
GlobalValue::ExternalLinkage, 0,
"XeTraceUserCall");
engine_->addGlobalMapping(gv, (void*)&XeTraceUserCall);
gv = new GlobalVariable(*gen_module_, traceInstructionTy, true,
GlobalValue::ExternalLinkage, 0,
"XeTraceInstruction");
engine_->addGlobalMapping(gv, (void*)&XeTraceInstruction);
return 0;
}