Compare commits

...

10 commits
v0.2 ... master

Author SHA1 Message Date
DataHoarder 875f6588d9 Implement proper Init OutputContext
All checks were successful
continuous-integration/drone/push Build is passing
2021-08-05 16:29:07 +02:00
DataHoarder 3868034b6b Update rrcc mappings for new set
All checks were successful
continuous-integration/drone/push Build is passing
2021-08-03 22:21:34 +02:00
DataHoarder 812d1d632f hide NOP bytes by default
All checks were successful
continuous-integration/drone/push Build is passing
2021-08-03 01:36:25 +02:00
DataHoarder 926b1d6a82 Decode new rrcc extended symbols with comments
All checks were successful
continuous-integration/drone/push Build is passing
2021-08-03 01:12:49 +02:00
DataHoarder 83a1b7d280 Fixed rrcc register naming
All checks were successful
continuous-integration/drone/push Build is passing
2021-08-03 00:26:32 +02:00
DataHoarder b019ab7684 Fixed Write command max length 2021-08-03 00:25:51 +02:00
DataHoarder 6a5d9696e7 Added more rrc-as register annotations
Some checks failed
continuous-integration/drone/push Build is failing
2021-08-02 21:05:34 +02:00
DataHoarder 6d3760c96e fixed several clang-tidy warnings
All checks were successful
continuous-integration/drone/push Build is passing
2021-08-01 20:18:57 +02:00
DataHoarder 2324a561f3 Added know NOP instructions to properly handle rrc-as symbols 2021-08-01 20:11:04 +02:00
DataHoarder bf7c3cefe5 Add virtual destructor to abstract Instruction class 2021-08-01 20:10:33 +02:00
17 changed files with 239 additions and 115 deletions

View file

@ -238,7 +238,7 @@ void ImageFormat::decodeAnalyzeInstructionsAt(uint32_t offset) {
if ((instruction->getCommand() == Instruction::Instruction::CommandOp::JUMP ||
instruction->getCommand() == Instruction::Instruction::CommandOp::RETURN) &&
jumpsUsed.find(instruction->getEndAddress()) == jumpsUsed.end()) {
jumpsUsed[instruction->getEndAddress()] = false;
jumpsUsed[instruction->getEndAddress()] = false; //TODO: remove this or make it opt-in by default
}
if (jumpsUsed.find(state.current) != jumpsUsed.end() && !jumpsUsed[state.current]) {

View file

@ -52,6 +52,10 @@ std::string OutputContext::getComment(uint32_t location) const {
return "";
}
bool OutputContext::isNop(uint32_t location) const {
return nop.find(location) != nop.end();
}
std::string OutputContext::getDataHeader(uint32_t location) const {
std::stringstream s;
@ -150,7 +154,7 @@ void OutputContext::analyze() {
if (writeInstruction.data.size() == 1 &&
writeInstruction.data[0] == e.first) { //Return value!
//TODO: mark join?
addComment(writeInstruction.getAddress() + 4, locText);
addComment(writeInstruction.getAddress() + 4, locText, true);
foundReturn = true;
break;
}
@ -172,7 +176,7 @@ void OutputContext::analyze() {
}
if (e.second.size() > 1 || (!hasContinue && !e.second.empty())) {
addComment(e.first, "<" + getLabel(e.first, true) + "> " + from.str());
addComment(e.first, "<" + getLabel(e.first, true) + "> " + from.str(), true);
}
}
@ -184,19 +188,29 @@ void OutputContext::addMapping(uint32_t location, const std::string &name, bool
}
}
void OutputContext::addComment(uint32_t location, const std::string &comment) {
void OutputContext::addComment(uint32_t location, const std::string &comment, bool force) {
if (comments.find(location) != comments.end()) {
comments[location] = comment + " --- " + comments[location];
comments[location] = force ? comment + " :: " + comments[location] : comments[location] + " :: " + comment;
} else {
comments[location] = comment;
}
}
void OutputContext::setNop(uint32_t location) {
nop[location] = true;
}
std::string OutputContext::getAddressRegisterName(uint32_t addr, uint8_t offset) const {
if (offset || registers.find(addr) == registers.end()) {
uint64_t k = (uint64_t)addr | ((uint64_t)offset << 32);
if (registers.find(k) == registers.end()) {
return ::getAddressRegisterName(addr, offset);
} else {
return registers.at(addr);
return registers.at(k);
}
}
void OutputContext::addRegister(const Instruction::AddressWithOffset &address, const std::string &name) {
registers[(uint64_t)address.address | ((uint64_t)address.offset << 32)] = name;
}

View file

@ -41,21 +41,22 @@ private:
const ImageFormat &image;
std::unordered_map<uint32_t, std::string> mappings;
std::unordered_map<uint32_t, std::string> comments;
std::unordered_map<uint32_t, std::string> registers;
std::unordered_map<uint64_t, std::string> registers;
std::unordered_map<uint32_t, bool> nop;
public:
OutputContext(const ImageFormat &image) : image(image) {
explicit OutputContext(const ImageFormat &image) : image(image) {
}
void addMapping(uint32_t location, const std::string &name, bool force = false);
void addComment(uint32_t location, const std::string &comment);
void addComment(uint32_t location, const std::string &comment, bool force = false);
void addRegister(uint32_t addr, const std::string &name) {
registers[addr] = name;
}
void setNop(uint32_t location);
void addRegister(const Instruction::AddressWithOffset& address, const std::string &name);
std::string getAddressRegisterName(uint32_t addr, uint8_t offset) const;
@ -69,6 +70,8 @@ public:
std::string getDataHeader(uint32_t location) const;
bool isNop(uint32_t location) const;
std::string getDataEntry(uint32_t location, const std::string &representation = "") const;
std::string getInstructionString(const Instruction::Instruction &instruction) const;

View file

@ -180,7 +180,7 @@ Instruction::Calc::execute(AnalysisState &state) const {
state.addKnownJump(getEndAddress(), getAddress(), JumpKind::Continue);
return std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>();
return {};
}
std::vector<uint8_t> Instruction::Calc::toBytes() const {

View file

@ -179,7 +179,7 @@ Instruction::CalcImm::execute(AnalysisState &state) const {
state.addKnownJump(getEndAddress(), getAddress(), JumpKind::Continue);
return std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>();
return {};
}
std::vector<uint8_t> Instruction::CalcImm::toBytes() const {

View file

@ -91,7 +91,7 @@ Instruction::Copy::execute(AnalysisState &state) const {
state.addKnownJump(getEndAddress(), getAddress(), JumpKind::Continue);
return std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>();
return {};
}

View file

@ -52,14 +52,14 @@ std::vector<Instruction::OutputFormat> Instruction::End::toOutputFormat(const Ou
}
std::vector<uint32_t> Instruction::End::getPossibleBranches() const {
return std::vector<uint32_t>();
return {};
}
std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>
Instruction::End::execute(AnalysisState &state) const {
state.current = 0;
return std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>();
return {};
}
std::vector<uint8_t> Instruction::End::toBytes() const {

View file

@ -29,6 +29,7 @@
#include "../Registers.h"
#include <iostream>
#include <iomanip>
#include "../OutputContext.h"
void Instruction::Init::fromBytes(uint32_t offset, const std::vector<uint8_t> &bytes) {
_address = offset;
@ -69,18 +70,35 @@ std::string Instruction::Init::toString() const {
if (count > 1 && increment) {
op << " UNTIL " << getAddressRegisterName(address + count - 1, addressOffset);
}
op << " COUNT " << std::hex << std::setw(6) << std::setfill('0') << count;
op << " INCREMENT " << std::dec << (uint32_t) increment;
op << " COUNT " << std::hex << std::setw(6) << std::setfill('0') << count;
op << " DATA 0x" << std::hex << std::setw(8) << std::setfill('0') << data;
op << " INC 0x" << std::hex << std::setw(8) << std::setfill('0') << data_add;
op << " ADD 0x" << std::hex << std::setw(8) << std::setfill('0') << data_add;
return op.str();
}
std::vector<Instruction::OutputFormat> Instruction::Init::toOutputFormat(const OutputContext &context) const {
return std::vector<OutputFormat>{
//TODO
std::vector<OutputFormat> f{
OutputFormat{getAddress() + 0 * 4,
dynamic_cast<std::stringstream &>(std::stringstream("") << "INIT" << " "
<< context.getAddressRegisterName(
address, addressOffset)
<< ", INC " << std::dec
<< (uint32_t) increment).str()}
};
f.emplace_back(OutputFormat{getAddress() + 1 * 4,
dynamic_cast<std::stringstream &>(std::stringstream("") << " COUNT " << std::dec
<< count).str()});
f.emplace_back(OutputFormat{getAddress() + 2 * 4,
dynamic_cast<std::stringstream &>(std::stringstream("") << " DATA 0x" << std::hex << std::setw(8) << std::setfill('0') << data).str()});
f.emplace_back(OutputFormat{getAddress() + 3 * 4,
dynamic_cast<std::stringstream &>(std::stringstream("") << " ADD 0x" << std::hex << std::setw(8) << std::setfill('0') << data_add).str()});
return f;
}
std::vector<uint32_t> Instruction::Init::getPossibleBranches() const {
@ -90,14 +108,14 @@ std::vector<uint32_t> Instruction::Init::getPossibleBranches() const {
std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>
Instruction::Init::execute(AnalysisState &state) const {
for (uint32_t i = 0; i < count; ++i) {
state.setRegister(address + (increment ? i : 0), data + data_add * i);
state.setRegister(address + increment, data + data_add * i);
}
state.current = _endAddress;
state.addKnownJump(getEndAddress(), getAddress(), JumpKind::Continue);
return std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>();
return {};
}
std::vector<uint8_t> Instruction::Init::toBytes() const {

View file

@ -54,11 +54,11 @@ namespace Instruction {
execute(AnalysisState &state) const override;
uint8_t addressOffset;
uint8_t increment;
uint32_t address;
uint32_t count;
uint32_t data;
uint32_t data_add;
uint8_t addressOffset{};
uint8_t increment{};
uint32_t address{};
uint32_t count{};
uint32_t data{};
uint32_t data_add{};
};
}

View file

@ -48,6 +48,8 @@ namespace Instruction {
uint32_t _endAddress{};
public:
virtual ~Instruction()= default;
enum class CommandOp : uint8_t {
WRITE = 0b00000000,
COPY = 0b01000000,

View file

@ -70,7 +70,7 @@ Instruction::Jump::execute(AnalysisState &state) const {
state.addKnownJump(jumpAddress, getAddress(), JumpKind::Absolute);
return std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>();
return {};
}
std::vector<uint8_t> Instruction::Jump::toBytes() const {

View file

@ -220,7 +220,7 @@ Instruction::Load::execute(AnalysisState &state) const {
state.addKnownJump(getEndAddress(), getAddress(), JumpKind::Continue);
return std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>();
return {};
}
std::vector<uint8_t> Instruction::Load::toBytes() const {

View file

@ -63,7 +63,7 @@ std::vector<Instruction::OutputFormat> Instruction::Return::toOutputFormat(const
}
std::vector<uint32_t> Instruction::Return::getPossibleBranches() const {
return std::vector<uint32_t>();
return {};
}
std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>
@ -73,7 +73,7 @@ Instruction::Return::execute(AnalysisState &state) const {
state.addKnownJump(jumpAddress, getAddress(), JumpKind::Return);
return std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>();
return {};
}

View file

@ -92,7 +92,7 @@ Instruction::Set::execute(AnalysisState &state) const {
state.addKnownJump(getEndAddress(), getAddress(), JumpKind::Continue);
return std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>();
return {};
}
std::vector<uint8_t> Instruction::Set::toBytes() const {

View file

@ -70,7 +70,7 @@ Instruction::Wait::execute(AnalysisState &state) const {
state.addKnownJump(getEndAddress(), getAddress(), JumpKind::Continue);
return std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>();
return {};
}
std::vector<uint8_t> Instruction::Wait::toBytes() const {

View file

@ -36,7 +36,7 @@ void Instruction::Write::fromBytes(uint32_t offset, const std::vector<uint8_t> &
uint32_t command = bytes[offset++];
uint8_t count = (1 + (command >> 2) & 0b1111);
uint8_t count = (1 + ((command >> 2) & 0b1111));
address.offset = command & 0b11;
address.address = bytes[offset++] << 16;
@ -108,7 +108,7 @@ Instruction::Write::execute(AnalysisState &state) const {
state.addKnownJump(getEndAddress(), getAddress(), JumpKind::Continue);
return std::vector<std::pair<uint32_t, std::unordered_map<uint32_t, uint32_t>>>();
return {};
}
std::vector<uint8_t> Instruction::Write::toBytes() const {

View file

@ -36,6 +36,23 @@
#include "OutputContext.h"
#include "instructions/End.h"
std::string ltrim(const std::string &s)
{
size_t start = s.find_first_not_of(" \n\r\t\f\v");
return (start == std::string::npos) ? "" : s.substr(start);
}
std::string rtrim(const std::string &s)
{
size_t end = s.find_last_not_of(" \n\r\t\f\v");
return (end == std::string::npos) ? "" : s.substr(0, end + 1);
}
std::string trim(const std::string &s) {
return rtrim(ltrim(s));
}
void decodeImage(const std::string &fileName) {
std::ifstream image(fileName);
@ -47,7 +64,7 @@ void decodeImage(const std::string &fileName) {
auto imageObject = ImageFormat::fromBytes(bytes);
printf("SPEED: 0x%02x MODE: 0x%02x BOOT: 0x%08x\n", imageObject.getHeader().speed, imageObject.getHeader().mode,
printf("SPEED: 0x%02x MODE: 0x%02x BOOT: 0x%08x\n", static_cast<uint32_t>(imageObject.getHeader().speed), static_cast<uint32_t>(imageObject.getHeader().mode),
imageObject.getHeader().baseAddress);
std::cout << "SIGNATURE: " << imageObject.imageSignature << "\n";
@ -299,80 +316,6 @@ void decodeImage(const std::string &fileName) {
};
bool isKnownAssembler = false;
if (imageObject.imageSignature.find("rrc-as") != std::string::npos) {
//Known assembler
isKnownAssembler = true;
comments.clear();
knownNames.clear();
for (auto& i : imageObject.getInstructions()){
std::unique_ptr<Instruction::Instruction> decodedInstruction = nullptr;
std::unique_ptr<Instruction::Instruction> decodedInstruction2 = nullptr;
const Instruction::End* endPointer = nullptr;
if(i.second->getCommand() == Instruction::Instruction::CommandOp::END){
endPointer = reinterpret_cast<const Instruction::End*>(i.second.get());
if(endPointer->reserved == 0 || endPointer->reserved == 0xFFFFFF){
endPointer = nullptr;
}
}
if(endPointer == nullptr && imageObject.findConstInstructionByAddress(i.second->getEndAddress(), false) == nullptr){
decodedInstruction = Instruction::Instruction::decodeInstructionFromBytes(i.second->getEndAddress(), imageObject.getBaseImage());
if(decodedInstruction != nullptr && decodedInstruction->getCommand() == Instruction::Instruction::CommandOp::END){
endPointer = reinterpret_cast<const Instruction::End*>(decodedInstruction.get());
if(endPointer->reserved == 0 || endPointer->reserved == 0xFFFFFF){
endPointer = nullptr;
}
}
}
if(endPointer != nullptr){ //Found backwards pointer
decodedInstruction2 = Instruction::Instruction::decodeInstructionFromBytes(endPointer->getEndAddress(), imageObject.getBaseImage());
if(decodedInstruction2 != nullptr && decodedInstruction2->getCommand() == Instruction::Instruction::CommandOp::LOAD){
auto loadPointer = reinterpret_cast<const Instruction::Load&>(*decodedInstruction2);
if(!loadPointer.increment && loadPointer.addressOffset == 0 && loadPointer.address == endPointer->getAddress()){ //found Function name
uint32_t functionStart = endPointer->reserved;
uint32_t functionEnd = loadPointer.address - 4;
std::string functionName;
for(auto& d : loadPointer.data){
uint8_t c = ((d >> 24) & 0xFF);
if(c == 0){
break;
}
functionName.push_back(c);
c = ((d >> 16) & 0xFF);
if(c == 0){
break;
}
functionName.push_back(c);
c = ((d >> 8) & 0xFF);
if(c == 0){
break;
}
functionName.push_back(c);
c = (d & 0xFF);
if(c == 0){
break;
}
functionName.push_back(c);
}
knownNames[functionStart] = functionName;
}
}
}
}
}
for (auto &e : knownNames) {
ctx.addMapping(e.first, e.second);
}
for (auto &c : comments) {
ctx.addComment(c.first, c.second);
}
for(uint32_t i = 10; i < 200; ++i){
if(registerRename.find((uint32_t) KnownRegisters::BSM_SCRATCH_START + i) == registerRename.end()){
std::stringstream s;
@ -406,7 +349,145 @@ void decodeImage(const std::string &fileName) {
}
for (auto &r : registerRename) {
ctx.addRegister(r.first, r.second);
ctx.addRegister(Instruction::AddressWithOffset{r.first, 0}, r.second);
}
bool isKnownAssembler = false;
if (imageObject.imageSignature.find("rrc-as") != std::string::npos) {
//Known assembler
isKnownAssembler = true;
comments.clear();
knownNames.clear();
ctx.addRegister(Instruction::AddressWithOffset{static_cast<uint32_t>(KnownRegisters::BSM_ADDR_OFFSET_3), 0}, "rrcc_STACK_POINTER");
ctx.addRegister(Instruction::AddressWithOffset{static_cast<uint32_t>(KnownRegisters::BSM_ADDR_OFFSET_2), 0}, "rrcc_FRAME_POINTER");
ctx.addRegister(Instruction::AddressWithOffset{static_cast<uint32_t>(KnownRegisters::MGMT_SCRATCH_0), 0}, "rrcc_SCRATCH_0");
ctx.addRegister(Instruction::AddressWithOffset{static_cast<uint32_t>(KnownRegisters::MGMT_SCRATCH_1), 0}, "rrcc_SCRATCH_1");
ctx.addRegister(Instruction::AddressWithOffset{static_cast<uint32_t>(KnownRegisters::BSM_SCRATCH_START) + 0x1E0, 0}, "rrcc_RETURN_VALUE");
ctx.addRegister(Instruction::AddressWithOffset{static_cast<uint32_t>(KnownRegisters::BSM_SCRATCH_START) + 0x1E1, 0}, "rrcc_RETURN_VALUE_EXTRA");
ctx.addRegister(Instruction::AddressWithOffset{static_cast<uint32_t>(KnownRegisters::BSM_SCRATCH_START) + 0x1E2, 0}, "rrcc_P0");
ctx.addRegister(Instruction::AddressWithOffset{static_cast<uint32_t>(KnownRegisters::BSM_SCRATCH_START) + 0x1E3, 0}, "rrcc_P1");
for(uint32_t i = 0; i < 16; ++i){
ctx.addRegister(Instruction::AddressWithOffset{i, 3}, "rrcc_STACK_POINTER+" +
std::to_string(i));
}
for(uint32_t i = 0; i < 16; ++i){
ctx.addRegister(Instruction::AddressWithOffset{i, 2}, "rrcc_FRAME_POINTER+" +
std::to_string(i));
}
for(uint32_t i = 0; i < 16; ++i){
ctx.addRegister(Instruction::AddressWithOffset{static_cast<uint32_t>(KnownRegisters::BSM_SCRATCH_START) + 0x1F0 + i, 0}, "rrcc_R" +
std::to_string(i));
}
for (auto& i : imageObject.getInstructions()){
std::unique_ptr<Instruction::Instruction> decodedInstruction = nullptr;
std::unique_ptr<Instruction::Instruction> decodedInstruction2 = nullptr;
const Instruction::End* endPointer = nullptr;
if(i.second->getCommand() == Instruction::Instruction::CommandOp::END){
endPointer = reinterpret_cast<const Instruction::End*>(i.second.get());
if(endPointer->reserved == 0 || endPointer->reserved == 0xFFFFFF){
endPointer = nullptr;
}
}
if(endPointer == nullptr && imageObject.findConstInstructionByAddress(i.second->getEndAddress(), false) == nullptr){
decodedInstruction = Instruction::Instruction::decodeInstructionFromBytes(i.second->getEndAddress(), imageObject.getBaseImage());
if(decodedInstruction != nullptr && decodedInstruction->getCommand() == Instruction::Instruction::CommandOp::END){
endPointer = reinterpret_cast<const Instruction::End*>(decodedInstruction.get());
if(endPointer->reserved != endPointer->getAddress()){
endPointer = nullptr;
}
}
}
if(endPointer != nullptr){ //Found backwards pointer
bool hasMore = true;
ctx.setNop(endPointer->getAddress());
uint32_t functionEnd = endPointer->reserved - 4;
uint32_t nextAddress = endPointer->getEndAddress();
do{
decodedInstruction2 = Instruction::Instruction::decodeInstructionFromBytes(nextAddress, imageObject.getBaseImage());
if(decodedInstruction2 != nullptr && decodedInstruction2->getCommand() == Instruction::Instruction::CommandOp::LOAD){
auto loadPointer = reinterpret_cast<const Instruction::Load&>(*decodedInstruction2);
for(auto nopAddr = loadPointer.getAddress(); nopAddr < loadPointer.getEndAddress(); nopAddr += 4){
ctx.setNop(nopAddr);
}
uint32_t targetAddress = loadPointer.address;
std::string stringData;
for(auto& d : loadPointer.data){
uint8_t c = ((d >> 24) & 0xFF);
if(c == 0){
break;
}
stringData.push_back(c);
c = ((d >> 16) & 0xFF);
if(c == 0){
break;
}
stringData.push_back(c);
c = ((d >> 8) & 0xFF);
if(c == 0){
break;
}
stringData.push_back(c);
c = (d & 0xFF);
if(c == 0){
break;
}
stringData.push_back(c);
}
switch (loadPointer.addressOffset) {
case 0: //FunctionName
knownNames[targetAddress] = stringData;
break;
case 1: //Comment
std::string s = stringData;
size_t pos = 0;
std::string token;
while ((pos = s.find('\n')) != std::string::npos) {
token = s.substr(0, pos);
auto trimmed = trim(token);
if(!trimmed.empty()){
ctx.addComment(targetAddress, trimmed);
}
s.erase(0, pos + 1);
}
auto trimmed = trim(s);
if(!trimmed.empty()){
ctx.addComment(targetAddress, trimmed);
}
break;
}
nextAddress = loadPointer.getEndAddress();
hasMore = loadPointer.increment == 1;
}else{
break;
}
} while (hasMore);
}
}
}
for (auto &e : knownNames) {
ctx.addMapping(e.first, e.second);
}
for (auto &c : comments) {
ctx.addComment(c.first, c.second);
}
ctx.analyze();
@ -414,7 +495,9 @@ void decodeImage(const std::string &fileName) {
uint32_t prevAddress = 0;
for (const auto &entry : imageObject.getInstructions()) {
const auto &instruction = entry.second;
if (instruction->getAddress() < prevAddress) {
if(ctx.isNop(instruction->getAddress())){
continue;
}else if (instruction->getAddress() < prevAddress) {
std::cout << "========== DECODE ERROR? ========== " << std::hex << std::setw(8) << std::setfill('0')
<< prevAddress << " - " << std::hex << std::setw(8) << std::setfill('0')
<< instruction->getAddress() << "\n";
@ -422,6 +505,10 @@ void decodeImage(const std::string &fileName) {
(instruction->getAddress() - prevAddress) < 1024) {
std::cout << "\n\n";
for (uint32_t addr = prevAddress; addr < instruction->getAddress(); addr += 4) {
if(ctx.isNop(addr)){
continue;
}
std::stringstream op;
std::string printable;
op << std::hex << std::setw(6) << std::setfill('0') << addr << " ";