mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
283 lines
8.5 KiB
C++
283 lines
8.5 KiB
C++
/// \file ptcdump.cpp
|
|
/// \brief This file handles dumping PTC to text
|
|
|
|
//
|
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
|
//
|
|
|
|
// Standard includes
|
|
#include <cassert>
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <iostream>
|
|
|
|
// Local includes
|
|
#include "ptcinterface.h"
|
|
|
|
static const int MAX_TEMP_NAME_LENGTH = 128;
|
|
|
|
static void getTemporaryName(char *Buffer, size_t BufferSize,
|
|
PTCInstructionList *Instructions,
|
|
unsigned TemporaryId) {
|
|
PTCTemp *Temporary = ptc_temp_get(Instructions, TemporaryId);
|
|
|
|
if (ptc_temp_is_global(Instructions, TemporaryId))
|
|
strncpy(Buffer, Temporary->name, BufferSize);
|
|
else if (Temporary->temp_local)
|
|
snprintf(Buffer, BufferSize, "loc%u",
|
|
TemporaryId - Instructions->global_temps);
|
|
else
|
|
snprintf(Buffer, BufferSize, "tmp%u",
|
|
TemporaryId - Instructions->global_temps);
|
|
}
|
|
|
|
int dumpInstruction(std::ostream& Result, PTCInstructionList *Instructions,
|
|
unsigned Index) {
|
|
size_t i = 0;
|
|
// TODO: this should stay in Architecture
|
|
int is64 = 0;
|
|
PTCInstruction& Instruction = Instructions->instructions[Index];
|
|
|
|
PTCOpcode Opcode = Instruction.opc;
|
|
PTCOpcodeDef *Definition = ptc_instruction_opcode_def(&ptc, &Instruction);
|
|
char TemporaryName[MAX_TEMP_NAME_LENGTH];
|
|
|
|
if (Opcode == PTC_INSTRUCTION_op_debug_insn_start) {
|
|
// TODO: create accessors for PTC_INSTRUCTION_op_debug_insn_start
|
|
uint64_t PC = Instruction.args[0];
|
|
|
|
if (is64)
|
|
PC |= Instruction.args[1] << 32;
|
|
|
|
Result << " ---- 0x" << std::hex << PC << std::endl;
|
|
} else if (Opcode == PTC_INSTRUCTION_op_call) {
|
|
// TODO: replace PRIx64 with PTC_PRIxARG
|
|
PTCInstructionArg FunctionPointer = 0;
|
|
FunctionPointer = ptc_call_instruction_const_arg(&ptc, &Instruction, 0);
|
|
PTCInstructionArg Flags = ptc_call_instruction_const_arg(&ptc,
|
|
&Instruction, 1);
|
|
size_t OutArgsCount = ptc_call_instruction_out_arg_count(&ptc,
|
|
&Instruction);
|
|
PTCHelperDef *Helper = ptc_find_helper(&ptc, FunctionPointer);
|
|
const char *HelperName = "unknown_helper";
|
|
|
|
if (Helper != nullptr && Helper->name != nullptr)
|
|
HelperName = Helper->name;
|
|
|
|
// The output format is:
|
|
// call name, flags, out_args_count, out_args [...], in_args [...]
|
|
Result << Definition->name
|
|
<< " " << HelperName
|
|
<< "," << "$0x" << std::hex << Flags
|
|
<< "," << std::dec << OutArgsCount;
|
|
|
|
// Print out arguments
|
|
for (i = 0; i < OutArgsCount; i++) {
|
|
getTemporaryName(TemporaryName, MAX_TEMP_NAME_LENGTH, Instructions,
|
|
ptc_call_instruction_out_arg(&ptc, &Instruction, i));
|
|
Result << "," << TemporaryName;
|
|
}
|
|
|
|
// Print in arguments
|
|
size_t InArgsCount = ptc_call_instruction_in_arg_count(&ptc, &Instruction);
|
|
for (i = 0; i < InArgsCount; i++) {
|
|
PTCInstructionArg InArg = ptc_call_instruction_in_arg(&ptc,
|
|
&Instruction, i);
|
|
|
|
if (InArg != PTC_CALL_DUMMY_ARG) {
|
|
getTemporaryName(TemporaryName, MAX_TEMP_NAME_LENGTH, Instructions,
|
|
InArg);
|
|
Result << "," << TemporaryName;
|
|
} else
|
|
Result << ",<dummy>";
|
|
}
|
|
|
|
} else {
|
|
// TODO: fix commas
|
|
Result << Definition->name << " ";
|
|
|
|
// Print out arguments
|
|
for (i = 0; i < ptc_instruction_out_arg_count(&ptc, &Instruction); i++) {
|
|
if (i != 0)
|
|
Result << ",";
|
|
|
|
getTemporaryName(TemporaryName, MAX_TEMP_NAME_LENGTH, Instructions,
|
|
ptc_instruction_out_arg(&ptc, &Instruction, i));
|
|
Result << TemporaryName;
|
|
}
|
|
|
|
if (i != 0)
|
|
Result << ",";
|
|
|
|
// Print in arguments
|
|
for (i = 0; i < ptc_instruction_in_arg_count(&ptc, &Instruction); i++) {
|
|
if (i != 0)
|
|
Result << ",";
|
|
|
|
getTemporaryName(TemporaryName, MAX_TEMP_NAME_LENGTH, Instructions,
|
|
ptc_instruction_in_arg(&ptc, &Instruction, i));
|
|
Result << TemporaryName;
|
|
}
|
|
|
|
if (i != 0)
|
|
Result << ",";
|
|
|
|
/* Parse some special const arguments */
|
|
i = 0;
|
|
switch (Opcode) {
|
|
case PTC_INSTRUCTION_op_brcond_i32:
|
|
case PTC_INSTRUCTION_op_setcond_i32:
|
|
case PTC_INSTRUCTION_op_movcond_i32:
|
|
case PTC_INSTRUCTION_op_brcond2_i32:
|
|
case PTC_INSTRUCTION_op_setcond2_i32:
|
|
case PTC_INSTRUCTION_op_brcond_i64:
|
|
case PTC_INSTRUCTION_op_setcond_i64:
|
|
case PTC_INSTRUCTION_op_movcond_i64:
|
|
{
|
|
PTCInstructionArg Arg = ptc_instruction_const_arg(&ptc,
|
|
&Instruction,
|
|
0);
|
|
PTCCondition ConditionId = static_cast<PTCCondition>(Arg);
|
|
const char *ConditionName = ptc.get_condition_name(ConditionId);
|
|
|
|
if (ConditionName != nullptr)
|
|
Result << "," << ConditionName;
|
|
else
|
|
Result << "," << "$0x" << std::hex << Arg;
|
|
|
|
/* Consume one argument */
|
|
i++;
|
|
break;
|
|
}
|
|
case PTC_INSTRUCTION_op_qemu_ld_i32:
|
|
case PTC_INSTRUCTION_op_qemu_st_i32:
|
|
case PTC_INSTRUCTION_op_qemu_ld_i64:
|
|
case PTC_INSTRUCTION_op_qemu_st_i64:
|
|
{
|
|
PTCInstructionArg Arg = ptc_instruction_const_arg(&ptc,
|
|
&Instruction, 0);
|
|
PTCLoadStoreArg LoadStoreArg = {};
|
|
LoadStoreArg = ptc.parse_load_store_arg(Arg);
|
|
|
|
if (LoadStoreArg.access_type == PTC_MEMORY_ACCESS_UNKNOWN)
|
|
Result << "," << "$0x" << std::hex << LoadStoreArg.raw_op;
|
|
else {
|
|
const char *Alignment = nullptr;
|
|
const char *LoadStoreName = nullptr;
|
|
LoadStoreName = ptc.get_load_store_name(LoadStoreArg.type);
|
|
|
|
switch (LoadStoreArg.access_type) {
|
|
case PTC_MEMORY_ACCESS_NORMAL:
|
|
Alignment = "";
|
|
break;
|
|
case PTC_MEMORY_ACCESS_UNALIGNED:
|
|
Alignment = "un+";
|
|
break;
|
|
case PTC_MEMORY_ACCESS_ALIGNED:
|
|
Alignment = "al+";
|
|
break;
|
|
default:
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
if (LoadStoreName == nullptr)
|
|
return EXIT_FAILURE;
|
|
|
|
Result << "," << Alignment << LoadStoreName;
|
|
}
|
|
|
|
Result << "," << LoadStoreArg.mmu_index;
|
|
|
|
/* Consume one argument */
|
|
i++;
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
switch (Opcode) {
|
|
case PTC_INSTRUCTION_op_set_label:
|
|
case PTC_INSTRUCTION_op_br:
|
|
case PTC_INSTRUCTION_op_brcond_i32:
|
|
case PTC_INSTRUCTION_op_brcond_i64:
|
|
case PTC_INSTRUCTION_op_brcond2_i32:
|
|
{
|
|
PTCInstructionArg Arg = ptc_instruction_const_arg(&ptc,
|
|
&Instruction,
|
|
i);
|
|
Result << "," << "$L" << ptc.get_arg_label_id(Arg);
|
|
|
|
/* Consume one more argument */
|
|
i++;
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/* Print remaining const arguments */
|
|
for (; i < ptc_instruction_const_arg_count(&ptc, &Instruction); i++) {
|
|
if (i != 0) {
|
|
Result << ",";
|
|
}
|
|
|
|
Result << "$0x" << std::hex
|
|
<< ptc_instruction_const_arg(&ptc, &Instruction, i);
|
|
}
|
|
|
|
}
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
void disassembleOriginal(std::ostream& Result, uint64_t PC) {
|
|
char *BufferPtr = nullptr;
|
|
size_t BufferLenPtr = 0;
|
|
FILE *MemoryStream = open_memstream(&BufferPtr, &BufferLenPtr);
|
|
|
|
assert(MemoryStream != nullptr);
|
|
|
|
// Using SIZE_MAX is not very nice but the code should disassemble only a
|
|
// single instruction nonetheless.
|
|
ptc.disassemble(MemoryStream, PC, SIZE_MAX, 1);
|
|
fflush(MemoryStream);
|
|
|
|
assert(BufferPtr != nullptr);
|
|
|
|
Result << BufferPtr;
|
|
|
|
fclose(MemoryStream);
|
|
free(BufferPtr);
|
|
}
|
|
|
|
int dumpTranslation(std::ostream& Result, PTCInstructionList *Instructions) {
|
|
// TODO: this should stay in Architecture
|
|
int is64 = 0;
|
|
|
|
for (unsigned Index = 0; Index < Instructions->instruction_count; Index++) {
|
|
PTCInstruction& Instruction = Instructions->instructions[Index];
|
|
PTCOpcode Opcode = Instruction.opc;
|
|
|
|
if (Opcode == PTC_INSTRUCTION_op_debug_insn_start) {
|
|
uint64_t PC = Instruction.args[0];
|
|
|
|
if (is64)
|
|
PC |= Instruction.args[1] << 32;
|
|
|
|
disassembleOriginal(Result, PC);
|
|
}
|
|
|
|
Result << std::dec << Index << ": ";
|
|
|
|
if (dumpInstruction(Result, Instructions, Index) == EXIT_FAILURE)
|
|
return EXIT_FAILURE;
|
|
|
|
Result << std::endl;
|
|
}
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|