Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 74 additions & 5 deletions core/adapters/corelliumadapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ using namespace BinaryNinja;
using namespace std;
using namespace BinaryNinjaDebugger;

static bool IsBigEndianArchitecture(const std::string& arch);

CorelliumAdapter::CorelliumAdapter(BinaryView* data, bool redirectGDBServer): DebugAdapter(data)
{
m_isTargetRunning = false;
Expand Down Expand Up @@ -93,17 +95,19 @@ bool CorelliumAdapter::LoadRegisterInfo()

std::string architecture{};
std::string os_abi{};
std::string endian{};
size_t lastRegIndex = -1;
for (auto node = doc.first_child().child("architecture"); node; node = node.next_sibling())
{
using namespace std::literals::string_literals;

if ( node.name() == "architecture"s )
architecture = node.child_value();
if ( node.name() == "osabi"s )
else if ( node.name() == "osabi"s )
os_abi = node.child_value();

if ( node.name() == "feature"s )
else if ( node.name() == "endian"s )
endian = node.child_value();
else if ( node.name() == "feature"s )
{
for (auto reg_child = node.child("reg"); reg_child; reg_child = reg_child.next_sibling())
{
Expand Down Expand Up @@ -134,6 +138,9 @@ bool CorelliumAdapter::LoadRegisterInfo()
if (architecture.empty())
throw std::runtime_error("failed to find architecture");

// Store the original architecture for endianness detection before stripping the prefix
std::string fullArchitecture = architecture;

if (architecture.find(':') != std::string::npos)
{
architecture.erase(0, architecture.find(':') + 1);
Expand All @@ -143,6 +150,12 @@ bool CorelliumAdapter::LoadRegisterInfo()
}
m_remoteArch = architecture;

// Determine endianness: prefer explicit <endian> element, fall back to architecture-based detection
if (!endian.empty())
m_isBigEndian = (endian == "big");
else
m_isBigEndian = IsBigEndianArchitecture(fullArchitecture);

std::unordered_map<std::uint32_t, std::string> id_name{};
std::unordered_map<std::uint32_t, std::uint32_t> id_width{};

Expand Down Expand Up @@ -438,6 +451,22 @@ bool CorelliumAdapter::BreakpointExists(uint64_t address) const
DebugBreakpoint(address)) != this->m_debugBreakpoints.end();
}

static bool IsBigEndianArchitecture(const std::string& arch) {
// PowerPC architectures (powerpc, ppc, common from "powerpc:common")
if (arch.find("powerpc") != std::string::npos || arch.find("ppc") != std::string::npos || arch == "common")
return true;
// SPARC
if (arch.find("sparc") != std::string::npos)
return true;
// Motorola 68k
if (arch.find("m68k") != std::string::npos || arch.find("68k") != std::string::npos)
return true;
// IBM S/390
if (arch.find("s390") != std::string::npos)
return true;
return false;
}

static intx::uint512 parseLittleEndianHexToUint512(const std::string& hex) {
if (hex.size() % 2 != 0)
return {};
Expand All @@ -456,6 +485,27 @@ static intx::uint512 parseLittleEndianHexToUint512(const std::string& hex) {
return intx::le::load<intx::uint512>(buffer);
}

static intx::uint512 parseBigEndianHexToUint512(const std::string& hex) {
if (hex.size() % 2 != 0)
return {};

uint8_t buffer[64] = {}; // Zero-initialized

size_t byteCount = hex.size() / 2;
size_t limit = std::min(byteCount, size_t(64));

// For big-endian: the hex string has MSB first. intx::be::load expects MSB at buffer[0]
// for a full 512-bit value, so we must right-justify the bytes in the buffer.
size_t offset = 64 - limit;
for (size_t i = 0; i < limit; ++i)
{
std::string byteStr = hex.substr(i * 2, 2);
buffer[offset + i] = static_cast<uint8_t>(strtoul(byteStr.c_str(), nullptr, 16));
}

return intx::be::load<intx::uint512>(buffer);
}

std::unordered_map<std::string, DebugRegister> CorelliumAdapter::ReadAllRegisters()
{
if (m_regCache.has_value())
Expand Down Expand Up @@ -485,7 +535,8 @@ std::unordered_map<std::string, DebugRegister> CorelliumAdapter::ReadAllRegister
const auto number_of_chars = 2 * ( register_info.m_bitSize / 8 );
const auto value_string = register_info_reply_string.substr(0, number_of_chars);
if (!value_string.empty()) {
intx::uint512 value = parseLittleEndianHexToUint512(value_string);
intx::uint512 value = m_isBigEndian ? parseBigEndianHexToUint512(value_string)
: parseLittleEndianHexToUint512(value_string);
all_regs[register_name] = DebugRegister(register_name, value, register_info.m_bitSize, register_info.m_regNum);
}
register_info_reply_string.erase(0, number_of_chars);
Expand Down Expand Up @@ -521,6 +572,23 @@ static std::string uint512ToLittleEndianHex(const intx::uint512& value, size_t w
return result;
}

static std::string uint512ToBigEndianHex(const intx::uint512& value, size_t width) {
// Truncate to 64 bytes (512 bits max)
if (width > 64)
width = 64;

uint8_t buffer[64] = {};
intx::be::store(buffer, value); // Store as big-endian

// For big-endian, we need to output starting from the correct offset to get 'width' bytes
size_t offset = 64 - width;
std::string result;
for (size_t i = 0; i < width; ++i)
result += fmt::format("{:02X}", buffer[offset + i]);

return result;
}

bool CorelliumAdapter::WriteRegister(const std::string& reg, intx::uint512 value)
{
if (m_isTargetRunning)
Expand All @@ -529,7 +597,8 @@ bool CorelliumAdapter::WriteRegister(const std::string& reg, intx::uint512 value
if (!this->m_registerInfo.contains(reg))
return false;

const auto newRegString = uint512ToLittleEndianHex(value, this->m_registerInfo[reg].m_bitSize / 8);
const auto newRegString = m_isBigEndian ? uint512ToBigEndianHex(value, this->m_registerInfo[reg].m_bitSize / 8)
: uint512ToLittleEndianHex(value, this->m_registerInfo[reg].m_bitSize / 8);
const auto reply = this->m_rspConnector->TransmitAndReceive(RspData("P{:02X}={}",
this->m_registerInfo[reg].m_regNum, newRegString));
if (reply.m_data[0])
Expand Down
4 changes: 4 additions & 0 deletions core/adapters/corelliumadapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ namespace BinaryNinjaDebugger
// support the case -- so we do not really lose a lot anyways.
std::string m_remoteArch;

// Whether the target uses big-endian byte order. Determined from target XML <endian> element
// or inferred from architecture name.
bool m_isBigEndian = false;

void InvalidateCache();

virtual DebugStopReason SignalToStopReason(std::unordered_map<std::string, std::uint64_t>& map);
Expand Down
75 changes: 73 additions & 2 deletions core/adapters/esrevenadapter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ using namespace BinaryNinja;
using namespace std;
using namespace BinaryNinjaDebugger;

static bool IsBigEndianArchitecture(const std::string& arch);

EsrevenAdapter::EsrevenAdapter(BinaryView* data, bool redirectGDBServer): DebugAdapter(data)
{
m_isTargetRunning = false;
Expand Down Expand Up @@ -95,6 +97,7 @@ bool EsrevenAdapter::LoadRegisterInfo()

std::string architecture{};
std::string os_abi{};
std::string endian{};
size_t lastRegIndex = -1;

auto processFeatures = [&](const pugi::xml_node& node) {
Expand Down Expand Up @@ -134,6 +137,8 @@ bool EsrevenAdapter::LoadRegisterInfo()
architecture = node.child_value();
else if ( node.name() == "osabi"s )
os_abi = node.child_value();
else if ( node.name() == "endian"s )
endian = node.child_value();
else if ( node.name() == "feature"s )
processFeatures(node);
else if (node.name() == "xi:include"s )
Expand All @@ -157,6 +162,9 @@ bool EsrevenAdapter::LoadRegisterInfo()
if (architecture.empty())
throw std::runtime_error("failed to find architecture");

// Store the original architecture for endianness detection before stripping the prefix
std::string fullArchitecture = architecture;

if (architecture.find(':') != std::string::npos)
{
architecture.erase(0, architecture.find(':') + 1);
Expand All @@ -166,6 +174,12 @@ bool EsrevenAdapter::LoadRegisterInfo()
}
m_remoteArch = architecture;

// Determine endianness: prefer explicit <endian> element, fall back to architecture-based detection
if (!endian.empty())
m_isBigEndian = (endian == "big");
else
m_isBigEndian = IsBigEndianArchitecture(fullArchitecture);

std::unordered_map<std::uint32_t, std::string> id_name{};
std::unordered_map<std::uint32_t, std::uint32_t> id_width{};

Expand Down Expand Up @@ -473,6 +487,22 @@ bool EsrevenAdapter::BreakpointExists(uint64_t address) const
DebugBreakpoint(address)) != this->m_debugBreakpoints.end();
}

static bool IsBigEndianArchitecture(const std::string& arch) {
// PowerPC architectures (powerpc, ppc, common from "powerpc:common")
if (arch.find("powerpc") != std::string::npos || arch.find("ppc") != std::string::npos || arch == "common")
return true;
// SPARC
if (arch.find("sparc") != std::string::npos)
return true;
// Motorola 68k
if (arch.find("m68k") != std::string::npos || arch.find("68k") != std::string::npos)
return true;
// IBM S/390
if (arch.find("s390") != std::string::npos)
return true;
return false;
}

static intx::uint512 parseLittleEndianHexToUint512(const std::string& hex) {
if (hex.size() % 2 != 0)
return {};
Expand All @@ -491,6 +521,27 @@ static intx::uint512 parseLittleEndianHexToUint512(const std::string& hex) {
return intx::le::load<intx::uint512>(buffer);
}

static intx::uint512 parseBigEndianHexToUint512(const std::string& hex) {
if (hex.size() % 2 != 0)
return {};

uint8_t buffer[64] = {}; // Zero-initialized

size_t byteCount = hex.size() / 2;
size_t limit = std::min(byteCount, size_t(64));

// For big-endian: the hex string has MSB first. intx::be::load expects MSB at buffer[0]
// for a full 512-bit value, so we must right-justify the bytes in the buffer.
size_t offset = 64 - limit;
for (size_t i = 0; i < limit; ++i)
{
std::string byteStr = hex.substr(i * 2, 2);
buffer[offset + i] = static_cast<uint8_t>(strtoul(byteStr.c_str(), nullptr, 16));
}

return intx::be::load<intx::uint512>(buffer);
}

std::unordered_map<std::string, DebugRegister> EsrevenAdapter::ReadAllRegisters()
{
if (m_isTargetRunning || !m_rspConnector)
Expand Down Expand Up @@ -523,7 +574,8 @@ std::unordered_map<std::string, DebugRegister> EsrevenAdapter::ReadAllRegisters(
const auto number_of_chars = 2 * ( register_info.m_bitSize / 8 );
const auto value_string = register_info_reply_string.substr(0, number_of_chars);
if (!value_string.empty()) {
intx::uint512 value = parseLittleEndianHexToUint512(value_string);
intx::uint512 value = m_isBigEndian ? parseBigEndianHexToUint512(value_string)
: parseLittleEndianHexToUint512(value_string);
all_regs[register_name] = DebugRegister(register_name, value, register_info.m_bitSize, register_info.m_regNum);
}
register_info_reply_string.erase(0, number_of_chars);
Expand Down Expand Up @@ -559,6 +611,24 @@ static std::string uint512ToLittleEndianHex(const intx::uint512& value, size_t w
return result;
}

static std::string uint512ToBigEndianHex(const intx::uint512& value, size_t width) {
// Truncate to 64 bytes (512 bits max)
if (width > 64)
width = 64;

uint8_t buffer[64] = {};
intx::be::store(buffer, value); // Store as big-endian

std::string result;
// For big-endian, we need to output from the position where the value starts
// The value is stored right-aligned in the 64-byte buffer
size_t offset = 64 - width;
for (size_t i = 0; i < width; ++i)
result += fmt::format("{:02X}", buffer[offset + i]);

return result;
}

bool EsrevenAdapter::WriteRegister(const std::string& reg, intx::uint512 value)
{
if (m_isTargetRunning || !m_rspConnector)
Expand All @@ -567,7 +637,8 @@ bool EsrevenAdapter::WriteRegister(const std::string& reg, intx::uint512 value)
if (!this->m_registerInfo.contains(reg))
return false;

const auto newRegString = uint512ToLittleEndianHex(value, this->m_registerInfo[reg].m_bitSize / 8);
const auto newRegString = m_isBigEndian ? uint512ToBigEndianHex(value, this->m_registerInfo[reg].m_bitSize / 8)
: uint512ToLittleEndianHex(value, this->m_registerInfo[reg].m_bitSize / 8);
const auto reply = this->m_rspConnector->TransmitAndReceive(RspData("P{:02X}={}",
this->m_registerInfo[reg].m_regNum, newRegString));

Expand Down
4 changes: 4 additions & 0 deletions core/adapters/esrevenadapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ namespace BinaryNinjaDebugger
// support the case -- so we do not really lose a lot anyways.
std::string m_remoteArch;

// Whether the target uses big-endian byte order. Determined from target XML <endian> element
// or inferred from architecture name.
bool m_isBigEndian = false;

bool m_canReverseContinue = false;
bool m_canReverseStep = false;

Expand Down
Loading