mirror of
https://github.com/jpd002/Play-.git
synced 2025-04-28 21:57:57 +03:00
238 lines
7.2 KiB
C++
238 lines
7.2 KiB
C++
#include <QHeaderView>
|
|
#include "string_format.h"
|
|
#include "KernelObjectListView.h"
|
|
#include "DebugUtils.h"
|
|
#include "QtDialogListWidget.h"
|
|
|
|
CKernelObjectListView::CKernelObjectListView(QWidget* parent)
|
|
: QTableView(parent)
|
|
{
|
|
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
|
setSelectionBehavior(QAbstractItemView::SelectRows);
|
|
connect(this, &QTableView::doubleClicked, this, &CKernelObjectListView::tableDoubleClick);
|
|
}
|
|
|
|
void CKernelObjectListView::HandleMachineStateChange()
|
|
{
|
|
Update();
|
|
}
|
|
|
|
void CKernelObjectListView::SetContext(CMIPS* context, CBiosDebugInfoProvider* biosDebugInfoProvider)
|
|
{
|
|
m_context = context;
|
|
m_biosDebugInfoProvider = biosDebugInfoProvider;
|
|
SetObjectType(BIOS_DEBUG_OBJECT_TYPE_NULL);
|
|
Update();
|
|
}
|
|
|
|
void CKernelObjectListView::SetObjectType(uint32 objectType)
|
|
{
|
|
m_objectType = objectType;
|
|
|
|
m_schema = m_biosDebugInfoProvider ? m_biosDebugInfoProvider->GetBiosObjectsDebugInfo() : BiosDebugObjectInfoMap();
|
|
if(!m_schema.empty() && (m_objectType != BIOS_DEBUG_OBJECT_TYPE_NULL))
|
|
{
|
|
auto objectType = m_schema[m_objectType];
|
|
assert(!objectType.fields.empty());
|
|
assert(objectType.fields[0].HasAttribute(BIOS_DEBUG_OBJECT_FIELD_ATTRIBUTE::IDENTIFIER));
|
|
|
|
std::vector<std::string> headers;
|
|
for(const auto& field : objectType.fields)
|
|
{
|
|
headers.push_back(field.name);
|
|
}
|
|
|
|
m_model = new CQtGenericTableModel(this, headers);
|
|
setModel(m_model);
|
|
|
|
auto header = horizontalHeader();
|
|
for(int i = 0; i < objectType.fields.size(); i++)
|
|
{
|
|
const auto& field = objectType.fields[i];
|
|
header->setSectionHidden(i, field.HasAttribute(BIOS_DEBUG_OBJECT_FIELD_ATTRIBUTE::HIDDEN));
|
|
if(
|
|
field.HasAttribute(BIOS_DEBUG_OBJECT_FIELD_ATTRIBUTE::LOCATION) ||
|
|
field.HasAttribute(BIOS_DEBUG_OBJECT_FIELD_ATTRIBUTE::POSSIBLE_STR_POINTER))
|
|
{
|
|
header->setSectionResizeMode(i, QHeaderView::Stretch);
|
|
}
|
|
else
|
|
{
|
|
header->setSectionResizeMode(i, QHeaderView::ResizeToContents);
|
|
}
|
|
}
|
|
verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
|
|
verticalHeader()->hide();
|
|
|
|
OnObjectTypeChanged(objectType.name.c_str());
|
|
}
|
|
else
|
|
{
|
|
setModel(nullptr);
|
|
OnObjectTypeChanged("No Object Type");
|
|
}
|
|
|
|
Update();
|
|
}
|
|
|
|
void CKernelObjectListView::Update()
|
|
{
|
|
if(m_model)
|
|
{
|
|
m_model->clear();
|
|
}
|
|
|
|
if(!m_biosDebugInfoProvider || (m_objectType == BIOS_DEBUG_OBJECT_TYPE_NULL) || (m_schema.empty())) return;
|
|
|
|
auto moduleInfos = m_biosDebugInfoProvider->GetModulesDebugInfo();
|
|
|
|
auto objects = m_biosDebugInfoProvider->GetBiosObjects(m_objectType);
|
|
auto objectType = m_schema[m_objectType];
|
|
for(const auto& object : objects)
|
|
{
|
|
assert(object.fields.size() == objectType.fields.size());
|
|
std::vector<std::string> data;
|
|
for(int fieldIdx = 0; fieldIdx < object.fields.size(); fieldIdx++)
|
|
{
|
|
const auto& fieldType = objectType.fields[fieldIdx];
|
|
const auto& field = object.fields[fieldIdx];
|
|
if(auto intValue = std::get_if<uint32>(&field))
|
|
{
|
|
assert(fieldType.type == BIOS_DEBUG_OBJECT_FIELD_TYPE::UINT32);
|
|
if(fieldType.HasAttribute(BIOS_DEBUG_OBJECT_FIELD_ATTRIBUTE::TEXT_ADDRESS))
|
|
{
|
|
auto locationString = DebugUtils::PrintAddressLocation(*intValue, m_context, moduleInfos);
|
|
data.push_back(locationString);
|
|
}
|
|
else if(fieldType.HasAttribute(BIOS_DEBUG_OBJECT_FIELD_ATTRIBUTE::DATA_ADDRESS))
|
|
{
|
|
data.push_back(string_format("0x%08X", *intValue));
|
|
}
|
|
else if(fieldType.HasAttribute(BIOS_DEBUG_OBJECT_FIELD_ATTRIBUTE::POSSIBLE_STR_POINTER))
|
|
{
|
|
std::string value;
|
|
if(CMIPSAnalysis::TryGetStringAtAddress(m_context, *intValue, value))
|
|
{
|
|
data.push_back(string_format("0x%08X (%s)", *intValue, value.c_str()));
|
|
}
|
|
else
|
|
{
|
|
data.push_back(string_format("0x%08X", *intValue));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
data.push_back(string_format("%u", *intValue));
|
|
}
|
|
}
|
|
else if(auto strValue = std::get_if<std::string>(&field))
|
|
{
|
|
assert(fieldType.type == BIOS_DEBUG_OBJECT_FIELD_TYPE::STRING);
|
|
data.push_back(*strValue);
|
|
}
|
|
}
|
|
bool added = m_model->addItem(data);
|
|
assert(added);
|
|
}
|
|
}
|
|
|
|
void CKernelObjectListView::tableDoubleClick(const QModelIndex& indexRow)
|
|
{
|
|
auto objectType = m_schema[m_objectType];
|
|
auto action = objectType.selectionAction;
|
|
if(action == BIOS_DEBUG_OBJECT_ACTION::NONE)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//Assuming col 0 has id (verified in SetObjectType)
|
|
auto fieldType = objectType.fields[0];
|
|
auto index = m_model->index(indexRow.row(), 0);
|
|
uint32 objectId = 0;
|
|
|
|
//TODO: Find a better way to fetch the id/key from the indexRow.
|
|
auto idCellValue = m_model->getItem(index);
|
|
if(fieldType.HasAttribute(BIOS_DEBUG_OBJECT_FIELD_ATTRIBUTE::DATA_ADDRESS))
|
|
{
|
|
objectId = std::strtoul(idCellValue.c_str(), nullptr, 16);
|
|
}
|
|
else
|
|
{
|
|
objectId = std::strtoul(idCellValue.c_str(), nullptr, 10);
|
|
}
|
|
|
|
auto objects = m_biosDebugInfoProvider->GetBiosObjects(m_objectType);
|
|
|
|
auto objectIterator = std::find_if(std::begin(objects), std::end(objects),
|
|
[&](const BIOS_DEBUG_OBJECT& object) {
|
|
assert(!object.fields.empty());
|
|
if(auto id = std::get_if<uint32>(&object.fields[0]))
|
|
{
|
|
return (*id) == objectId;
|
|
}
|
|
return false;
|
|
});
|
|
if(objectIterator == std::end(objects)) return;
|
|
|
|
const auto& object(*objectIterator);
|
|
|
|
switch(action)
|
|
{
|
|
case BIOS_DEBUG_OBJECT_ACTION::SHOW_LOCATION:
|
|
{
|
|
int locationFieldIndex = objectType.FindFieldWithAttribute(BIOS_DEBUG_OBJECT_FIELD_ATTRIBUTE::LOCATION);
|
|
assert(locationFieldIndex != -1);
|
|
auto location = std::get_if<uint32>(&object.fields[locationFieldIndex]);
|
|
assert(location);
|
|
OnGotoAddress(*location);
|
|
}
|
|
break;
|
|
case BIOS_DEBUG_OBJECT_ACTION::SHOW_STACK_OR_LOCATION:
|
|
{
|
|
int pcFieldIndex = objectType.FindFieldWithAttribute(BIOS_DEBUG_OBJECT_FIELD_ATTRIBUTE::LOCATION);
|
|
int spFieldIndex = objectType.FindFieldWithAttribute(BIOS_DEBUG_OBJECT_FIELD_ATTRIBUTE::STACK_POINTER);
|
|
int raFieldIndex = objectType.FindFieldWithAttribute(BIOS_DEBUG_OBJECT_FIELD_ATTRIBUTE::RETURN_ADDRESS);
|
|
|
|
assert(pcFieldIndex != -1);
|
|
assert(spFieldIndex != -1);
|
|
assert(raFieldIndex != -1);
|
|
|
|
auto pc = std::get_if<uint32>(&object.fields[pcFieldIndex]);
|
|
auto sp = std::get_if<uint32>(&object.fields[spFieldIndex]);
|
|
auto ra = std::get_if<uint32>(&object.fields[raFieldIndex]);
|
|
|
|
assert(pc && sp && ra);
|
|
|
|
auto callStackItems = CMIPSAnalysis::GetCallStack(m_context, *pc, *sp, *ra);
|
|
if(callStackItems.size() <= 1)
|
|
{
|
|
OnGotoAddress(*pc);
|
|
}
|
|
else
|
|
{
|
|
std::map<std::string, uint32> addrMap;
|
|
QtDialogListWidget dialog(this);
|
|
for(auto itemIterator(std::begin(callStackItems));
|
|
itemIterator != std::end(callStackItems); itemIterator++)
|
|
{
|
|
const auto& item(*itemIterator);
|
|
std::string locationString = DebugUtils::PrintAddressLocation(item, m_context, m_biosDebugInfoProvider->GetModulesDebugInfo());
|
|
dialog.addItem(locationString);
|
|
addrMap.insert({locationString, item});
|
|
}
|
|
|
|
dialog.exec();
|
|
auto locationString = dialog.getResult();
|
|
if(!locationString.empty())
|
|
{
|
|
auto address = addrMap.at(locationString);
|
|
OnGotoAddress(address);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
assert(false);
|
|
break;
|
|
}
|
|
}
|