[compiler] asm-only disasm output + fix spacing bug (#3104)

This commit is contained in:
ManDude 2023-10-29 10:16:14 +00:00 committed by GitHub
parent 7c74b0c999
commit 09536c68ac
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 47 additions and 21 deletions

View file

@ -17,6 +17,14 @@
) )
) )
(defmacro mda (file &rest path)
"Make Debug Asm Only: make + print disassembly (asm-only mode) for a file"
(if (null? path)
`(asm-file ,file :color :write :disassemble :disasm-code-only)
`(asm-file ,file :color :write :disassemble :disasm-code-only ,(first path))
)
)
(defmacro ml (file) (defmacro ml (file)
"Make Load: make and load the file through the listener" "Make Load: make and load the file through the listener"
`(asm-file ,file :color :load :write) `(asm-file ,file :color :load :write)

View file

@ -324,13 +324,14 @@ std::vector<u8> Compiler::codegen_object_file(FileEnv* env) {
bool Compiler::codegen_and_disassemble_object_file(FileEnv* env, bool Compiler::codegen_and_disassemble_object_file(FileEnv* env,
std::vector<u8>* data_out, std::vector<u8>* data_out,
std::string* asm_out) { std::string* asm_out,
bool omit_ir) {
auto debug_info = &m_debugger.get_debug_info_for_object(env->name()); auto debug_info = &m_debugger.get_debug_info_for_object(env->name());
debug_info->clear(); debug_info->clear();
CodeGenerator gen(env, debug_info, m_version); CodeGenerator gen(env, debug_info, m_version);
*data_out = gen.run(&m_ts); *data_out = gen.run(&m_ts);
bool ok = true; bool ok = true;
*asm_out = debug_info->disassemble_all_functions(&ok, &m_goos.reader); *asm_out = debug_info->disassemble_all_functions(&ok, &m_goos.reader, omit_ir);
return ok; return ok;
} }
@ -482,7 +483,7 @@ void Compiler::asm_file(const CompilationOptions& options) {
std::vector<u8> data; std::vector<u8> data;
std::string disasm; std::string disasm;
if (options.disassemble) { if (options.disassemble) {
codegen_and_disassemble_object_file(obj_file, &data, &disasm); codegen_and_disassemble_object_file(obj_file, &data, &disasm, options.disasm_code_only);
if (options.disassembly_output_file.empty()) { if (options.disassembly_output_file.empty()) {
printf("%s\n", disasm.c_str()); printf("%s\n", disasm.c_str());
} else { } else {

View file

@ -34,6 +34,7 @@ struct CompilationOptions {
bool write = false; // write object file to out/obj bool write = false; // write object file to out/obj
bool no_code = false; // file shouldn't generate code, throw error if it does bool no_code = false; // file shouldn't generate code, throw error if it does
bool disassemble = false; // either print disassembly to stdout or output_file bool disassemble = false; // either print disassembly to stdout or output_file
bool disasm_code_only = false; // if on, IR and source lines are not printed
bool print_time = false; // print timing statistics bool print_time = false; // print timing statistics
}; };
@ -210,7 +211,8 @@ class Compiler {
std::vector<u8> codegen_object_file(FileEnv* env); std::vector<u8> codegen_object_file(FileEnv* env);
bool codegen_and_disassemble_object_file(FileEnv* env, bool codegen_and_disassemble_object_file(FileEnv* env,
std::vector<u8>* data_out, std::vector<u8>* data_out,
std::string* asm_out); std::string* asm_out,
bool omit_ir);
void for_each_in_list(const goos::Object& list, void for_each_in_list(const goos::Object& list,
const std::function<void(const goos::Object&)>& f); const std::function<void(const goos::Object&)>& f);

View file

@ -161,6 +161,8 @@ Val* Compiler::compile_asm_file(const goos::Object& form, const goos::Object& re
} else if (setting == ":disassemble") { } else if (setting == ":disassemble") {
options.disassemble = true; options.disassemble = true;
last_was_disasm = true; last_was_disasm = true;
} else if (setting == ":disasm-code-only") {
options.disasm_code_only = true;
} else { } else {
throw_compiler_error(form, "The option {} was not recognized for asm-file.", setting); throw_compiler_error(form, "The option {} was not recognized for asm-file.", setting);
} }

View file

@ -7,19 +7,22 @@
DebugInfo::DebugInfo(std::string obj_name) : m_obj_name(std::move(obj_name)) {} DebugInfo::DebugInfo(std::string obj_name) : m_obj_name(std::move(obj_name)) {}
std::string FunctionDebugInfo::disassemble_debug_info(bool* had_failure, std::string FunctionDebugInfo::disassemble_debug_info(bool* had_failure,
const goos::Reader* reader) { const goos::Reader* reader,
bool omit_ir) {
std::string result = fmt::format("[{}]\n", name); std::string result = fmt::format("[{}]\n", name);
result += result += disassemble_x86_function(generated_code.data(), generated_code.size(), reader, 0x10000,
disassemble_x86_function(generated_code.data(), generated_code.size(), reader, 0x10000, 0x10000, instructions, code_sources, ir_strings, had_failure,
0x10000, instructions, code_sources, ir_strings, had_failure, true); true, omit_ir);
return result; return result;
} }
std::string DebugInfo::disassemble_all_functions(bool* had_failure, const goos::Reader* reader) { std::string DebugInfo::disassemble_all_functions(bool* had_failure,
const goos::Reader* reader,
bool omit_ir) {
std::string result; std::string result;
for (auto& kv : m_functions) { for (auto& kv : m_functions) {
result += kv.second.disassemble_debug_info(had_failure, reader) + "\n\n"; result += kv.second.disassemble_debug_info(had_failure, reader, omit_ir) + "\n\n";
} }
return result; return result;
} }
@ -30,7 +33,7 @@ std::string DebugInfo::disassemble_function_by_name(const std::string& name,
std::string result; std::string result;
for (auto& kv : m_functions) { for (auto& kv : m_functions) {
if (kv.second.name == name) { if (kv.second.name == name) {
result += kv.second.disassemble_debug_info(had_failure, reader) + "\n\n"; result += kv.second.disassemble_debug_info(had_failure, reader, false) + "\n\n";
} }
} }
return result; return result;

View file

@ -40,7 +40,7 @@ struct FunctionDebugInfo {
std::vector<u8> generated_code; std::vector<u8> generated_code;
std::optional<int> stack_usage; std::optional<int> stack_usage;
std::string disassemble_debug_info(bool* had_failure, const goos::Reader* reader); std::string disassemble_debug_info(bool* had_failure, const goos::Reader* reader, bool omit_ir);
}; };
class DebugInfo { class DebugInfo {
@ -74,7 +74,9 @@ class DebugInfo {
void clear() { m_functions.clear(); } void clear() { m_functions.clear(); }
std::string disassemble_all_functions(bool* had_failure, const goos::Reader* reader); std::string disassemble_all_functions(bool* had_failure,
const goos::Reader* reader,
bool omit_ir);
std::string disassemble_function_by_name(const std::string& name, std::string disassemble_function_by_name(const std::string& name,
bool* had_failure, bool* had_failure,
const goos::Reader* reader); const goos::Reader* reader);

View file

@ -428,7 +428,7 @@ Disassembly Debugger::disassemble_at_rip(const InstructionPointerInfo& info) {
function_mem.data(), function_mem.size(), m_reader, function_mem.data(), function_mem.size(), m_reader,
m_debug_context.base + info.map_entry->start_addr + func_info->offset_in_seg, m_debug_context.base + info.map_entry->start_addr + func_info->offset_in_seg,
rip + rip_offset, func_info->instructions, func_info->code_sources, func_info->ir_strings, rip + rip_offset, func_info->instructions, func_info->code_sources, func_info->ir_strings,
&result.failed, false); &result.failed, false, false);
} }
} else { } else {
result.failed = true; result.failed = true;

View file

@ -76,6 +76,8 @@ std::string disassemble_x86(u8* data, int len, u64 base_addr, u64 highlight_addr
// how many "forms" to look at ahead of / behind rip when stopping // 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_REV = 4;
static constexpr int FORM_DUMP_SIZE_FWD = 4; static constexpr int FORM_DUMP_SIZE_FWD = 4;
// how long the bytecode part of the disassembly is, IR comes after this
static constexpr int DISASM_LINE_LEN = 60;
std::string disassemble_x86_function( std::string disassemble_x86_function(
u8* data, u8* data,
@ -87,7 +89,8 @@ std::string disassemble_x86_function(
const std::vector<std::shared_ptr<goos::HeapObject>>& code_sources, const std::vector<std::shared_ptr<goos::HeapObject>>& code_sources,
const std::vector<std::string>& ir_strings, const std::vector<std::string>& ir_strings,
bool* had_failure, bool* had_failure,
bool print_whole_function) { bool print_whole_function,
bool omit_ir) {
std::string result; std::string result;
ZydisDecoder decoder; ZydisDecoder decoder;
ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_STACK_WIDTH_64); ZydisDecoderInit(&decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_STACK_WIDTH_64);
@ -145,7 +148,8 @@ std::string disassemble_x86_function(
} }
} }
if (current_instruction_idx >= 0 && current_instruction_idx < int(x86_instructions.size())) { if (!omit_ir && current_instruction_idx >= 0 &&
current_instruction_idx < int(x86_instructions.size())) {
const auto& debug_instr = x86_instructions.at(current_instruction_idx); const auto& debug_instr = x86_instructions.at(current_instruction_idx);
if (debug_instr.kind == InstructionInfo::Kind::IR && debug_instr.ir_idx != current_ir_idx) { if (debug_instr.kind == InstructionInfo::Kind::IR && debug_instr.ir_idx != current_ir_idx) {
current_ir_idx = debug_instr.ir_idx; current_ir_idx = debug_instr.ir_idx;
@ -154,8 +158,9 @@ std::string disassemble_x86_function(
} }
std::string line; std::string line;
size_t line_size_offset = 0;
if (current_ir_idx >= 0 && current_ir_idx < int(ir_strings.size())) { if (!omit_ir && current_ir_idx >= 0 && current_ir_idx < int(ir_strings.size())) {
auto source = reader->db.try_get_short_info(code_sources.at(current_ir_idx)); auto source = reader->db.try_get_short_info(code_sources.at(current_ir_idx));
if (source) { if (source) {
if (source->filename != current_filename || if (source->filename != current_filename ||
@ -171,6 +176,7 @@ std::string disassemble_x86_function(
std::string pointer(current_offset_in_line + 3, ' '); std::string pointer(current_offset_in_line + 3, ' ');
pointer += "^\n"; pointer += "^\n";
line += fmt::format(fmt::emphasis::bold | fg(fmt::color::lime_green), "{}", pointer); line += fmt::format(fmt::emphasis::bold | fg(fmt::color::lime_green), "{}", pointer);
line_size_offset = line.size();
} }
} }
} }
@ -188,8 +194,8 @@ std::string disassemble_x86_function(
line += print_buff; line += print_buff;
if (print_ir && current_ir_idx >= 0 && current_ir_idx < int(ir_strings.size())) { if (print_ir && current_ir_idx >= 0 && current_ir_idx < int(ir_strings.size())) {
if (line.size() < 50) { if (line.size() - line_size_offset < DISASM_LINE_LEN) {
line.append(50 - line.size(), ' '); line.append(DISASM_LINE_LEN - (line.size() - line_size_offset), ' ');
} }
line += " "; line += " ";
line += ir_strings.at(current_ir_idx); line += ir_strings.at(current_ir_idx);

View file

@ -42,4 +42,5 @@ std::string disassemble_x86_function(
const std::vector<std::shared_ptr<goos::HeapObject>>& code_sources, const std::vector<std::shared_ptr<goos::HeapObject>>& code_sources,
const std::vector<std::string>& ir_strings, const std::vector<std::string>& ir_strings,
bool* had_failure, bool* had_failure,
bool print_whole_function); bool print_whole_function,
bool omit_ir);

View file

@ -292,7 +292,8 @@ TEST_F(WithGameTests, DebuggerMemoryMap) {
TEST_F(WithGameTests, DebuggerDisassemble) { TEST_F(WithGameTests, DebuggerDisassemble) {
auto di = shared_compiler->compiler.get_debugger().get_debug_info_for_object("gcommon"); auto di = shared_compiler->compiler.get_debugger().get_debug_info_for_object("gcommon");
bool fail = false; bool fail = false;
auto result = di.disassemble_all_functions(&fail, &shared_compiler->compiler.get_goos().reader); auto result =
di.disassemble_all_functions(&fail, &shared_compiler->compiler.get_goos().reader, false);
// printf("Got\n%s\n", result.c_str()); // printf("Got\n%s\n", result.c_str());
EXPECT_FALSE(fail); EXPECT_FALSE(fail);
} }