DataHoarder
926b1d6a82
All checks were successful
continuous-integration/drone/push Build is passing
217 lines
8.7 KiB
C++
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;
|
|
}
|