mirror of https://github.com/stella-emu/stella.git
Start work on ELF debug widget.
This commit is contained in:
parent
d64ff2e5b7
commit
36ebe43f16
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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 \
|
||||
|
|
|
@ -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<ElfLinker>(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"
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue