mirror of
https://github.com/open-goal/jak-project.git
synced 2024-10-20 11:26:18 -04:00
80a002f8c0
* make birthing work * fix float representation on defskelgroup * test * update * debugger improvements & dont upload aux sprites * ? * fix progress * fixes * fixes * Create bea.gd * fix test * fix xmm reg clobbering in kernel (water) * cleanup cam-start * clear gamepad state every frame * allow controller connects and disconnects while running
206 lines
7.3 KiB
C++
206 lines
7.3 KiB
C++
#include "disassemble.h"
|
|
#include "Zydis/Zydis.h"
|
|
#include "third-party/fmt/core.h"
|
|
#include "goalc/compiler/Env.h"
|
|
#include "goalc/compiler/IR.h"
|
|
#include "common/goos/Reader.h"
|
|
#include "third-party/fmt/color.h"
|
|
|
|
std::string disassemble_x86(u8* data, int len, u64 base_addr) {
|
|
std::string result;
|
|
ZydisDecoder decoder;
|
|
ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_ADDRESS_WIDTH_64);
|
|
ZydisFormatter formatter;
|
|
ZydisFormatterInit(&formatter, ZYDIS_FORMATTER_STYLE_INTEL);
|
|
ZydisDecodedInstruction instr;
|
|
|
|
constexpr int print_buff_size = 512;
|
|
char print_buff[print_buff_size];
|
|
int offset = 0;
|
|
while (ZYAN_SUCCESS(ZydisDecoderDecodeBuffer(&decoder, data + offset, len - offset, &instr))) {
|
|
result += fmt::format("[0x{:x}] ", base_addr);
|
|
ZydisFormatterFormatInstruction(&formatter, &instr, print_buff, print_buff_size, base_addr);
|
|
result += print_buff;
|
|
result += "\n";
|
|
|
|
offset += instr.length;
|
|
base_addr += instr.length;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
std::string disassemble_x86(u8* data, int len, u64 base_addr, u64 highlight_addr) {
|
|
std::string result;
|
|
ZydisDecoder decoder;
|
|
ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_ADDRESS_WIDTH_64);
|
|
ZydisFormatter formatter;
|
|
ZydisFormatterInit(&formatter, ZYDIS_FORMATTER_STYLE_INTEL);
|
|
ZydisDecodedInstruction instr;
|
|
|
|
constexpr int print_buff_size = 512;
|
|
char print_buff[print_buff_size];
|
|
int offset = 0;
|
|
|
|
assert(highlight_addr >= base_addr);
|
|
int mark_offset = int(highlight_addr - base_addr);
|
|
while (offset < len) {
|
|
char prefix = (offset == mark_offset) ? '-' : ' ';
|
|
if (ZYAN_SUCCESS(ZydisDecoderDecodeBuffer(&decoder, data + offset, len - offset, &instr))) {
|
|
result += fmt::format("{:c} [0x{:x}] ", prefix, base_addr);
|
|
ZydisFormatterFormatInstruction(&formatter, &instr, print_buff, print_buff_size, base_addr);
|
|
result += print_buff;
|
|
result += "\n";
|
|
offset += instr.length;
|
|
base_addr += instr.length;
|
|
} else {
|
|
result += fmt::format("{:c} [0x{:x}] INVALID (0x{:02x})\n", prefix, base_addr, data[offset]);
|
|
offset++;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// how many "forms" to look at ahead of / behind rip when stopping
|
|
static constexpr int FORM_DUMP_SIZE_REV = 4;
|
|
static constexpr int FORM_DUMP_SIZE_FWD = 4;
|
|
|
|
std::string disassemble_x86_function(u8* data,
|
|
int len,
|
|
const goos::Reader* reader,
|
|
u64 base_addr,
|
|
u64 highlight_addr,
|
|
const std::vector<InstructionInfo>& x86_instructions,
|
|
const FunctionEnv* fenv,
|
|
bool* had_failure) {
|
|
std::string result;
|
|
ZydisDecoder decoder;
|
|
ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_ADDRESS_WIDTH_64);
|
|
ZydisFormatter formatter;
|
|
ZydisFormatterInit(&formatter, ZYDIS_FORMATTER_STYLE_INTEL);
|
|
ZydisDecodedInstruction instr;
|
|
|
|
const auto& irs = fenv->code();
|
|
|
|
constexpr int print_buff_size = 512;
|
|
char print_buff[print_buff_size];
|
|
int offset = 0;
|
|
|
|
int current_instruction_idx = -1;
|
|
int current_ir_idx = -1;
|
|
int current_src_idx = -1;
|
|
int rip_src_idx = -1;
|
|
|
|
std::string current_filename;
|
|
int current_file_line = -1;
|
|
int current_offset_in_line = -1;
|
|
|
|
std::vector<std::pair<int, std::string>> lines;
|
|
|
|
assert(highlight_addr >= base_addr);
|
|
int mark_offset = int(highlight_addr - base_addr);
|
|
while (offset < len) {
|
|
char prefix = (offset == mark_offset) ? '-' : ' ';
|
|
if (ZYAN_SUCCESS(ZydisDecoderDecodeBuffer(&decoder, data + offset, len - offset, &instr))) {
|
|
bool warn_messed_up = false;
|
|
bool print_ir = false;
|
|
// we should have a next instruction.
|
|
if (current_instruction_idx + 1 >= int(x86_instructions.size())) {
|
|
warn_messed_up = true;
|
|
if (had_failure) {
|
|
*had_failure = true;
|
|
}
|
|
} else {
|
|
// we should line up with the next instruction
|
|
if (x86_instructions.at(current_instruction_idx + 1).offset == offset) {
|
|
// perfect, everything is lined up!
|
|
current_instruction_idx++;
|
|
while (current_instruction_idx + 1 < int(x86_instructions.size()) &&
|
|
x86_instructions.at(current_instruction_idx + 1).offset == offset) {
|
|
current_instruction_idx++;
|
|
}
|
|
} else {
|
|
printf("offset mess up, at %d, expected %d\n", offset,
|
|
x86_instructions.at(current_instruction_idx + 1).offset);
|
|
warn_messed_up = true;
|
|
if (had_failure) {
|
|
*had_failure = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (current_instruction_idx >= 0 && current_instruction_idx < int(x86_instructions.size())) {
|
|
const auto& debug_instr = x86_instructions.at(current_instruction_idx);
|
|
if (debug_instr.kind == InstructionInfo::Kind::IR && debug_instr.ir_idx != current_ir_idx) {
|
|
current_ir_idx = debug_instr.ir_idx;
|
|
print_ir = true;
|
|
}
|
|
}
|
|
|
|
std::string line;
|
|
|
|
if (current_ir_idx >= 0 && current_ir_idx < int(irs.size())) {
|
|
auto source = reader->db.try_get_short_info(fenv->code_source().at(current_ir_idx));
|
|
if (source) {
|
|
if (source->filename != current_filename ||
|
|
source->line_idx_to_display != current_file_line ||
|
|
source->pos_in_line != current_offset_in_line) {
|
|
current_filename = source->filename;
|
|
current_file_line = source->line_idx_to_display;
|
|
current_offset_in_line = source->pos_in_line;
|
|
++current_src_idx;
|
|
line +=
|
|
fmt::format(fmt::emphasis::bold, "\n{}:{}\n", current_filename, current_file_line);
|
|
line += fmt::format(fg(fmt::color::orange), "-> {}\n", source->line_text);
|
|
std::string pointer(current_offset_in_line + 3, ' ');
|
|
pointer += "^\n";
|
|
line += fmt::format(fmt::emphasis::bold | fg(fmt::color::lime_green), "{}", pointer);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (prefix != ' ') {
|
|
line += fmt::format(fmt::emphasis::bold | fg(fmt::color::red), "{:c} [0x{:X}] ", prefix,
|
|
base_addr);
|
|
rip_src_idx = current_src_idx;
|
|
} else {
|
|
line += fmt::format("{:c} [0x{:X}] ", prefix, base_addr);
|
|
}
|
|
|
|
ZydisFormatterFormatInstruction(&formatter, &instr, print_buff, print_buff_size, base_addr);
|
|
line += print_buff;
|
|
|
|
if (print_ir && current_ir_idx >= 0 && current_ir_idx < int(irs.size())) {
|
|
if (line.size() < 50) {
|
|
line.append(50 - line.size(), ' ');
|
|
}
|
|
line += " ";
|
|
line += irs.at(current_ir_idx)->print();
|
|
}
|
|
|
|
if (warn_messed_up) {
|
|
line += " ;; function's instruction do not align with debug data, something is wrong.";
|
|
}
|
|
line += "\n";
|
|
lines.push_back(std::make_pair(current_src_idx, line));
|
|
offset += instr.length;
|
|
base_addr += instr.length;
|
|
} else {
|
|
lines.push_back(std::make_pair(
|
|
current_src_idx,
|
|
fmt::format("{:c} [0x{:x}] INVALID (0x{:02x})\n", prefix, base_addr, data[offset])));
|
|
offset++;
|
|
}
|
|
}
|
|
|
|
for (auto& line : lines) {
|
|
if (line.first >= rip_src_idx - FORM_DUMP_SIZE_REV &&
|
|
line.first < rip_src_idx + FORM_DUMP_SIZE_FWD) {
|
|
result.append(line.second);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|