rrcSmall/src/OutputContext.cpp
DataHoarder 926b1d6a82
All checks were successful
continuous-integration/drone/push Build is passing
Decode new rrcc extended symbols with comments
2021-08-03 01:12:49 +02:00

217 lines
8.7 KiB
C++

/*****************************************************************************
* Copyright (c) 2020, rrcSmall FM10K-Documentation Contributors
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the copyright holder nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/
#include <sstream>
#include <iomanip>
#include "OutputContext.h"
#include "instructions/Write.h"
#include "instructions/Jump.h"
#include "Registers.h"
std::string OutputContext::getLabel(uint32_t location, bool force) const {
if (mappings.find(location) != mappings.end() && (!force || !mappings.at(location).empty())) {
return mappings.at(location);
}
if (force) {
std::stringstream s;
s << "loc_" << std::hex << std::setw(6) << std::setfill('0') << location;
return s.str();
}
return "";
}
std::string OutputContext::getComment(uint32_t location) const {
if (comments.find(location) != comments.end()) {
return " ; " + comments.at(location);
}
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;
s << std::hex << std::setw(6) << std::setfill('0') << location << " ";
for (uint32_t i = location; i < location + 4; ++i) {
s << std::hex << std::setw(2) << std::setfill('0') << (uint32_t) image.getBaseImage().at(i) << " ";
}
s << " ";
return s.str();
}
std::string OutputContext::getDataEntry(uint32_t location, const std::string &representation) const {
std::string result = getDataHeader(location) + representation;
uint32_t padLength = 80;
if (result.size() < padLength) {
result.append(padLength - result.size(), ' ');
}
result += getComment(location);
return result;
}
std::string OutputContext::getInstructionString(const Instruction::Instruction &instruction) const {
std::string output;
for (auto &l : instruction.toOutputFormat(*this)) {
output += getDataEntry(l.location, l.format) + "\n";
}
return output;
}
void OutputContext::analyze() {
const auto &table = image.getJumpTable();
for (auto &e : table) {
std::stringstream from;
from << "XREF.CallFrom: ";
bool hasContinue = false;
bool justAbsolute = true;
bool justReturn = true;
for (auto &j : e.second) {
if (j.second != JumpKind::Return && j.second != JumpKind::Speculative) {
justReturn = false;
}
if (j.second != JumpKind::Absolute && j.second != JumpKind::Speculative) {
justAbsolute = false;
}
if (j.second != JumpKind::Continue) {
from << std::hex << std::setw(6) << std::setfill('0') << j.first << "(";
switch (j.second) {
case JumpKind::Speculative:
from << "Speculative";
break;
case JumpKind::Absolute:
from << "Absolute";
break;
case JumpKind::Branch:
from << "Branch";
break;
case JumpKind::Loop:
from << "Loop";
break;
case JumpKind::Return:
from << "Return";
break;
case JumpKind::Interrupt:
from << "Interrupt";
break;
}
from << "), ";
} else {
hasContinue = true;
}
}
if (justReturn || justAbsolute) {
if (!e.second.empty() && justReturn) {
auto &instruction = image.findConstInstructionByAddress(e.first - 1, true);
if (instruction != nullptr && (instruction->getCommand() == Instruction::Instruction::CommandOp::JUMP ||
instruction->getCommand() ==
Instruction::Instruction::CommandOp::RETURN)) {
std::string locText = "RETURN location for call";
bool foundReturn = false;
uint32_t addressLocation = instruction->getAddress() - 1;
if (instruction->getCommand() == Instruction::Instruction::CommandOp::JUMP) {
auto &jumpInstruction = dynamic_cast<const Instruction::Jump &>(*instruction);
locText = "RETURN location for " + getLabel(jumpInstruction.jumpAddress);
}
while (true) {
auto &instructionBefore = image.findConstInstructionByAddress(addressLocation, true);
if (instructionBefore != nullptr &&
instructionBefore->getCommand() == Instruction::Instruction::CommandOp::WRITE) {
auto &writeInstruction = dynamic_cast<const Instruction::Write &>(*instructionBefore);
if (writeInstruction.data.size() == 1 &&
writeInstruction.data[0] == e.first) { //Return value!
//TODO: mark join?
addComment(writeInstruction.getAddress() + 4, locText, true);
foundReturn = true;
break;
}
addressLocation = instructionBefore->getAddress() - 1;
} else {
break;
}
}
if (!foundReturn) {
addMapping(e.first, getLabel(e.first, true));
}
} else {
addMapping(e.first, getLabel(e.first, true));
}
} else {
addMapping(e.first, getLabel(e.first, true));
}
}
if (e.second.size() > 1 || (!hasContinue && !e.second.empty())) {
addComment(e.first, "<" + getLabel(e.first, true) + "> " + from.str(), true);
}
}
}
void OutputContext::addMapping(uint32_t location, const std::string &name, bool force) {
if (mappings.find(location) == comments.end() || (force && !mappings[location].empty())) {
mappings[location] = name;
}
}
void OutputContext::addComment(uint32_t location, const std::string &comment, bool force) {
if (comments.find(location) != comments.end()) {
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 {
uint64_t k = (uint64_t)addr | ((uint64_t)offset << 32);
if (registers.find(k) == registers.end()) {
return ::getAddressRegisterName(addr, offset);
} else {
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;
}