From 36ebe43f16603f21755477c0a1daef4bd0d7a015 Mon Sep 17 00:00:00 2001 From: Christian Speckner Date: Tue, 20 Aug 2024 18:49:47 +0200 Subject: [PATCH] Start work on ELF debug widget. --- src/debugger/gui/CartELFWidget.cxx | 53 +++++++++++++++++++ src/debugger/gui/CartELFWidget.hxx | 45 +++++++++++++++++ src/debugger/gui/module.mk | 1 + src/emucore/CartELF.cxx | 81 ++++++++++++++++++++---------- src/emucore/CartELF.hxx | 17 +++++++ 5 files changed, 171 insertions(+), 26 deletions(-) create mode 100644 src/debugger/gui/CartELFWidget.cxx create mode 100644 src/debugger/gui/CartELFWidget.hxx diff --git a/src/debugger/gui/CartELFWidget.cxx b/src/debugger/gui/CartELFWidget.cxx new file mode 100644 index 000000000..85e5c9858 --- /dev/null +++ b/src/debugger/gui/CartELFWidget.cxx @@ -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); +} diff --git a/src/debugger/gui/CartELFWidget.hxx b/src/debugger/gui/CartELFWidget.hxx new file mode 100644 index 000000000..e3adf8f26 --- /dev/null +++ b/src/debugger/gui/CartELFWidget.hxx @@ -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 diff --git a/src/debugger/gui/module.mk b/src/debugger/gui/module.mk index f7fb85c5c..39fa861d5 100644 --- a/src/debugger/gui/module.mk +++ b/src/debugger/gui/module.mk @@ -48,6 +48,7 @@ MODULE_OBJS := \ src/debugger/gui/CartFCWidget.o \ src/debugger/gui/CartFEWidget.o \ src/debugger/gui/CartGLWidget.o \ + src/debugger/gui/CartELFWidget.o \ src/debugger/gui/CartJANEWidget.o \ src/debugger/gui/CartMDMWidget.o \ src/debugger/gui/CartRamWidget.o \ diff --git a/src/emucore/CartELF.cxx b/src/emucore/CartELF.cxx index 131437046..baeea7359 100644 --- a/src/emucore/CartELF.cxx +++ b/src/emucore/CartELF.cxx @@ -26,6 +26,10 @@ #include "Settings.hxx" #include "exception/FatalEmulationError.hxx" +#ifdef DEBUGGER_SUPPORT + #include "CartELFWidget.hxx" +#endif + #include "CartELF.hxx" using namespace elfEnvironment; @@ -35,22 +39,22 @@ namespace { constexpr uInt32 ARM_RUNAHED_MIN = 3; 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; for (const auto& section: elf.getSections()) { - if (section.type != 0x00) cout << i << " " << section << '\n'; + if (section.type != 0x00) stream << i << " " << section << '\n'; i++; } auto symbols = elf.getSymbols(); - cout << "\nELF symbols:\n\n"; + stream << "\nELF symbols:\n\n"; if (!symbols.empty()) { i = 0; for (auto& symbol: symbols) - cout << (i++) << " " << symbol << '\n'; + stream << (i++) << " " << symbol << '\n'; } i = 0; @@ -58,25 +62,25 @@ namespace { auto rels = elf.getRelocations(i++); if (!rels) continue; - cout + stream << "\nELF relocations for section " << 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) << "\ndata segment size: 0x" << std::setw(8) << linker.getSegmentSize(ElfLinker::SegmentType::data) << "\nrodata segment size: 0x" << std::setw(8) << linker.getSegmentSize(ElfLinker::SegmentType::rodata) << '\n'; - cout << "\nrelocated sections:\n\n"; + stream << "\nrelocated sections:\n\n"; const auto& sections = parser.getSections(); const auto& relocatedSections = linker.getRelocatedSections(); @@ -84,14 +88,14 @@ namespace { for (size_t i = 0; i < sections.size(); i++) { if (!relocatedSections[i]) continue; - cout + stream << sections[i].name << " @ 0x"<< std::setw(8) << (relocatedSections[i]->offset + linker.getSegmentBase(relocatedSections[i]->segment)) << " 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& relocatedSymbols = linker.getRelocatedSymbols(); @@ -99,49 +103,49 @@ namespace { for (size_t i = 0; i < symbols.size(); i++) { if (!relocatedSymbols[i]) continue; - cout + stream << symbols[i].name << " = 0x" << std::setw(8) << relocatedSymbols[i]->value; if (relocatedSymbols[i]->segment) { switch (*relocatedSymbols[i]->segment) { case ElfLinker::SegmentType::text: - cout << " (text)"; + stream << " (text)"; break; case ElfLinker::SegmentType::data: - cout << " (data)"; + stream << " (data)"; break; case ElfLinker::SegmentType::rodata: - cout << " (rodata)"; + stream << " (rodata)"; break; } } else { - cout << " (abs)"; + stream << " (abs)"; } - cout << '\n'; + stream << '\n'; } const auto& initArray = linker.getInitArray(); const auto& preinitArray = linker.getPreinitArray(); if (!initArray.empty()) { - cout << "\ninit array:\n\n"; + stream << "\ninit array:\n\n"; for (const uInt32 address: initArray) - cout << " * 0x" << std::setw(8) << address << '\n'; + stream << " * 0x" << std::setw(8) << address << '\n'; } if (!preinitArray.empty()) { - cout << "\npreinit array:\n\n"; + stream << "\npreinit array:\n\n"; 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) @@ -370,6 +374,31 @@ uInt8 CartridgeELF::overdrivePoke(uInt16 address, uInt8 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 { @@ -412,7 +441,7 @@ void CartridgeELF::parseAndLinkElf() throw runtime_error("failed to initialize ELF: " + string(e.what())); } - if (dump) dumpElf(myElfParser); + if (dump) dumpElf(myElfParser, cout); myLinker = make_unique(ADDR_TEXT_BASE, ADDR_DATA_BASE, ADDR_RODATA_BASE, myElfParser); try { @@ -437,7 +466,7 @@ void CartridgeELF::parseAndLinkElf() throw runtime_error("rodata segment too large"); if (dump) { - dumpLinkage(myElfParser, *myLinker); + dumpLinkage(myElfParser, *myLinker, cout); cout << "\nARM entrypoint: 0x" diff --git a/src/emucore/CartELF.hxx b/src/emucore/CartELF.hxx index 97cb93500..aaee2305d 100644 --- a/src/emucore/CartELF.hxx +++ b/src/emucore/CartELF.hxx @@ -28,7 +28,15 @@ class ElfLinker; +#ifdef DEBUGGER_SUPPORT + class CartridgeELFWidget; +#endif + class CartridgeELF: public Cartridge { +#ifdef DEBUGGER_SUPPORT + friend CartridgeELFWidget; +#endif + public: static constexpr uInt32 MIPS_MAX = 300; static constexpr uInt32 MIPS_MIN = 50; @@ -72,6 +80,15 @@ class CartridgeELF: public Cartridge { 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: class BusFallbackDelegate: public CortexM0::BusTransactionDelegate { public: