Start work on ELF debug widget.

This commit is contained in:
Christian Speckner 2024-08-20 18:49:47 +02:00
parent d64ff2e5b7
commit 36ebe43f16
5 changed files with 171 additions and 26 deletions

View File

@ -0,0 +1,53 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#include "CartELFWidget.hxx"
#include "CartELF.hxx"
#include "Widget.hxx"
#include "StringParser.hxx"
#include "ScrollBarWidget.hxx"
#include "StringListWidget.hxx"
CartridgeELFWidget::CartridgeELFWidget(GuiObject* boss, const GUI::Font& lfont,
const GUI::Font& nfont,
int x, int y, int w, int h,
CartridgeELF& cart)
: CartDebugWidget(boss, lfont, nfont, x, y, w, h)
{
addBaseInformation(cart.myImageSize, "AtariAge", "see log below", 1);
const auto lineHeight = lfont.getLineHeight();
const auto logWidth = _w - 12;
constexpr uInt32 visibleLogLines = 20;
const StringParser parser(
cart.getDebugLog(),
(logWidth - ScrollBarWidget::scrollBarWidth(lfont)) / lfont.getMaxCharWidth()
);
const auto& logLines = parser.stringList();
const bool useScrollbar = logLines.size() > visibleLogLines;
auto logWidget = new StringListWidget(
boss, lfont, 2, (9 * lineHeight) / 2, logWidth, visibleLogLines * lineHeight, false, useScrollbar
);
logWidget->setEditable(false);
logWidget->setEnabled(true);
logWidget->setList(logLines);
}

View File

@ -0,0 +1,45 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2024 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================
#ifndef CART_ELF_WIDGET_HXX
#define CART_ELF_WIDGET_HXX
#include "CartDebugWidget.hxx"
class CartridgeELF;
class CartridgeELFWidget: public CartDebugWidget
{
public:
CartridgeELFWidget(GuiObject* boss, const GUI::Font& lfont,
const GUI::Font& nfont,
int x, int y, int w, int h,
CartridgeELF& cart);
~CartridgeELFWidget() override = default;
private:
CartridgeELFWidget() = delete;
CartridgeELFWidget(const CartridgeELFWidget&) = delete;
CartridgeELFWidget(CartridgeELFWidget&&) = delete;
CartridgeELFWidget& operator=(const CartridgeELFWidget&) = delete;
CartridgeELFWidget& operator=(CartridgeELFWidget&&) = delete;
};
#endif // CART_ELF_WIDGET_HXX

View File

@ -48,6 +48,7 @@ MODULE_OBJS := \
src/debugger/gui/CartFCWidget.o \ src/debugger/gui/CartFCWidget.o \
src/debugger/gui/CartFEWidget.o \ src/debugger/gui/CartFEWidget.o \
src/debugger/gui/CartGLWidget.o \ src/debugger/gui/CartGLWidget.o \
src/debugger/gui/CartELFWidget.o \
src/debugger/gui/CartJANEWidget.o \ src/debugger/gui/CartJANEWidget.o \
src/debugger/gui/CartMDMWidget.o \ src/debugger/gui/CartMDMWidget.o \
src/debugger/gui/CartRamWidget.o \ src/debugger/gui/CartRamWidget.o \

View File

@ -26,6 +26,10 @@
#include "Settings.hxx" #include "Settings.hxx"
#include "exception/FatalEmulationError.hxx" #include "exception/FatalEmulationError.hxx"
#ifdef DEBUGGER_SUPPORT
#include "CartELFWidget.hxx"
#endif
#include "CartELF.hxx" #include "CartELF.hxx"
using namespace elfEnvironment; using namespace elfEnvironment;
@ -35,22 +39,22 @@ namespace {
constexpr uInt32 ARM_RUNAHED_MIN = 3; constexpr uInt32 ARM_RUNAHED_MIN = 3;
constexpr uInt32 ARM_RUNAHED_MAX = 6; constexpr uInt32 ARM_RUNAHED_MAX = 6;
void dumpElf(const ElfFile& elf) void dumpElf(const ElfFile& elf, ostream& stream)
{ {
cout << "\nELF sections:\n\n"; stream << "\nELF sections:\n\n";
size_t i = 0; size_t i = 0;
for (const auto& section: elf.getSections()) { for (const auto& section: elf.getSections()) {
if (section.type != 0x00) cout << i << " " << section << '\n'; if (section.type != 0x00) stream << i << " " << section << '\n';
i++; i++;
} }
auto symbols = elf.getSymbols(); auto symbols = elf.getSymbols();
cout << "\nELF symbols:\n\n"; stream << "\nELF symbols:\n\n";
if (!symbols.empty()) { if (!symbols.empty()) {
i = 0; i = 0;
for (auto& symbol: symbols) for (auto& symbol: symbols)
cout << (i++) << " " << symbol << '\n'; stream << (i++) << " " << symbol << '\n';
} }
i = 0; i = 0;
@ -58,25 +62,25 @@ namespace {
auto rels = elf.getRelocations(i++); auto rels = elf.getRelocations(i++);
if (!rels) continue; if (!rels) continue;
cout stream
<< "\nELF relocations for section " << "\nELF relocations for section "
<< section.name << ":\n\n"; << section.name << ":\n\n";
for (auto& rel: *rels) cout << rel << '\n'; for (auto& rel: *rels) stream << rel << '\n';
} }
} }
void dumpLinkage(const ElfParser& parser, const ElfLinker& linker) void dumpLinkage(const ElfParser& parser, const ElfLinker& linker, ostream& stream)
{ {
cout << std::hex << std::setfill('0'); stream << std::hex << std::setfill('0');
cout stream
<< "\ntext segment size: 0x" << std::setw(8) << linker.getSegmentSize(ElfLinker::SegmentType::text) << "\ntext segment size: 0x" << std::setw(8) << linker.getSegmentSize(ElfLinker::SegmentType::text)
<< "\ndata segment size: 0x" << std::setw(8) << linker.getSegmentSize(ElfLinker::SegmentType::data) << "\ndata segment size: 0x" << std::setw(8) << linker.getSegmentSize(ElfLinker::SegmentType::data)
<< "\nrodata segment size: 0x" << std::setw(8) << linker.getSegmentSize(ElfLinker::SegmentType::rodata) << "\nrodata segment size: 0x" << std::setw(8) << linker.getSegmentSize(ElfLinker::SegmentType::rodata)
<< '\n'; << '\n';
cout << "\nrelocated sections:\n\n"; stream << "\nrelocated sections:\n\n";
const auto& sections = parser.getSections(); const auto& sections = parser.getSections();
const auto& relocatedSections = linker.getRelocatedSections(); const auto& relocatedSections = linker.getRelocatedSections();
@ -84,14 +88,14 @@ namespace {
for (size_t i = 0; i < sections.size(); i++) { for (size_t i = 0; i < sections.size(); i++) {
if (!relocatedSections[i]) continue; if (!relocatedSections[i]) continue;
cout stream
<< sections[i].name << sections[i].name
<< " @ 0x"<< std::setw(8) << " @ 0x"<< std::setw(8)
<< (relocatedSections[i]->offset + linker.getSegmentBase(relocatedSections[i]->segment)) << (relocatedSections[i]->offset + linker.getSegmentBase(relocatedSections[i]->segment))
<< " size 0x" << std::setw(8) << sections[i].size << '\n'; << " size 0x" << std::setw(8) << sections[i].size << '\n';
} }
cout << "\nrelocated symbols:\n\n"; stream << "\nrelocated symbols:\n\n";
const auto& symbols = parser.getSymbols(); const auto& symbols = parser.getSymbols();
const auto& relocatedSymbols = linker.getRelocatedSymbols(); const auto& relocatedSymbols = linker.getRelocatedSymbols();
@ -99,49 +103,49 @@ namespace {
for (size_t i = 0; i < symbols.size(); i++) { for (size_t i = 0; i < symbols.size(); i++) {
if (!relocatedSymbols[i]) continue; if (!relocatedSymbols[i]) continue;
cout stream
<< symbols[i].name << symbols[i].name
<< " = 0x" << std::setw(8) << relocatedSymbols[i]->value; << " = 0x" << std::setw(8) << relocatedSymbols[i]->value;
if (relocatedSymbols[i]->segment) { if (relocatedSymbols[i]->segment) {
switch (*relocatedSymbols[i]->segment) { switch (*relocatedSymbols[i]->segment) {
case ElfLinker::SegmentType::text: case ElfLinker::SegmentType::text:
cout << " (text)"; stream << " (text)";
break; break;
case ElfLinker::SegmentType::data: case ElfLinker::SegmentType::data:
cout << " (data)"; stream << " (data)";
break; break;
case ElfLinker::SegmentType::rodata: case ElfLinker::SegmentType::rodata:
cout << " (rodata)"; stream << " (rodata)";
break; break;
} }
} else { } else {
cout << " (abs)"; stream << " (abs)";
} }
cout << '\n'; stream << '\n';
} }
const auto& initArray = linker.getInitArray(); const auto& initArray = linker.getInitArray();
const auto& preinitArray = linker.getPreinitArray(); const auto& preinitArray = linker.getPreinitArray();
if (!initArray.empty()) { if (!initArray.empty()) {
cout << "\ninit array:\n\n"; stream << "\ninit array:\n\n";
for (const uInt32 address: initArray) for (const uInt32 address: initArray)
cout << " * 0x" << std::setw(8) << address << '\n'; stream << " * 0x" << std::setw(8) << address << '\n';
} }
if (!preinitArray.empty()) { if (!preinitArray.empty()) {
cout << "\npreinit array:\n\n"; stream << "\npreinit array:\n\n";
for (const uInt32 address: preinitArray) for (const uInt32 address: preinitArray)
cout << " * 0x" << std::setw(8) << address << '\n'; stream << " * 0x" << std::setw(8) << address << '\n';
} }
cout << std::dec; stream << std::dec;
} }
void writeDebugBinary(const ElfLinker& linker) void writeDebugBinary(const ElfLinker& linker)
@ -370,6 +374,31 @@ uInt8 CartridgeELF::overdrivePoke(uInt16 address, uInt8 value)
return driveBus(address, value); return driveBus(address, value);
} }
#ifdef DEBUGGER_SUPPORT
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CartDebugWidget* CartridgeELF::debugWidget(
GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h
) {
return new CartridgeELFWidget(boss, lfont, nfont, x, y, w, h, *this);
}
string CartridgeELF::getDebugLog() const
{
ostringstream s;
s
<< "ARM entrypoint: 0x"
<< std::hex << std::setw(8) << std::setfill('0') << myArmEntrypoint
<< std::dec << '\n';
dumpLinkage(myElfParser, *myLinker, s);
return s.str();
}
#endif
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline uInt64 CartridgeELF::getArmCycles() const inline uInt64 CartridgeELF::getArmCycles() const
{ {
@ -412,7 +441,7 @@ void CartridgeELF::parseAndLinkElf()
throw runtime_error("failed to initialize ELF: " + string(e.what())); throw runtime_error("failed to initialize ELF: " + string(e.what()));
} }
if (dump) dumpElf(myElfParser); if (dump) dumpElf(myElfParser, cout);
myLinker = make_unique<ElfLinker>(ADDR_TEXT_BASE, ADDR_DATA_BASE, ADDR_RODATA_BASE, myElfParser); myLinker = make_unique<ElfLinker>(ADDR_TEXT_BASE, ADDR_DATA_BASE, ADDR_RODATA_BASE, myElfParser);
try { try {
@ -437,7 +466,7 @@ void CartridgeELF::parseAndLinkElf()
throw runtime_error("rodata segment too large"); throw runtime_error("rodata segment too large");
if (dump) { if (dump) {
dumpLinkage(myElfParser, *myLinker); dumpLinkage(myElfParser, *myLinker, cout);
cout cout
<< "\nARM entrypoint: 0x" << "\nARM entrypoint: 0x"

View File

@ -28,7 +28,15 @@
class ElfLinker; class ElfLinker;
#ifdef DEBUGGER_SUPPORT
class CartridgeELFWidget;
#endif
class CartridgeELF: public Cartridge { class CartridgeELF: public Cartridge {
#ifdef DEBUGGER_SUPPORT
friend CartridgeELFWidget;
#endif
public: public:
static constexpr uInt32 MIPS_MAX = 300; static constexpr uInt32 MIPS_MAX = 300;
static constexpr uInt32 MIPS_MIN = 50; static constexpr uInt32 MIPS_MIN = 50;
@ -72,6 +80,15 @@ class CartridgeELF: public Cartridge {
bool doesBusStuffing() override { return true; } bool doesBusStuffing() override { return true; }
#ifdef DEBUGGER_SUPPORT
CartDebugWidget* debugWidget(
GuiObject* boss, const GUI::Font& lfont, const GUI::Font& nfont, int x, int y, int w, int h
) override;
#endif
public:
string getDebugLog() const;
private: private:
class BusFallbackDelegate: public CortexM0::BusTransactionDelegate { class BusFallbackDelegate: public CortexM0::BusTransactionDelegate {
public: public: