mirror of
https://github.com/wiiu-env/WiiUPluginLoaderBackend.git
synced 2026-03-22 01:35:55 -05:00
692 lines
27 KiB
C++
692 lines
27 KiB
C++
#include "ShellCommands.h"
|
|
|
|
#include "globals.h"
|
|
#include "plugin/ButtonComboManager.h"
|
|
#include "plugin/FunctionData.h"
|
|
#include "plugin/HookData.h"
|
|
#include "plugin/PluginContainer.h"
|
|
#include "plugin/PluginData.h"
|
|
#include "plugin/SectionInfo.h"
|
|
#include "utils/StringTools.h"
|
|
#include "utils/utils.h"
|
|
|
|
#include <iopshell/api.h>
|
|
|
|
#include <coreinit/debug.h>
|
|
|
|
#include <memory>
|
|
#include <numeric>
|
|
#include <optional>
|
|
#include <zconf.h>
|
|
|
|
namespace {
|
|
std::string toString(WUPSButtonCombo_ComboType type) {
|
|
switch (type) {
|
|
case WUPS_BUTTON_COMBO_COMBO_TYPE_INVALID:
|
|
return "Invalid";
|
|
case WUPS_BUTTON_COMBO_COMBO_TYPE_HOLD:
|
|
return "Hold";
|
|
case WUPS_BUTTON_COMBO_COMBO_TYPE_HOLD_OBSERVER:
|
|
return "Hold (Observer)";
|
|
case WUPS_BUTTON_COMBO_COMBO_TYPE_PRESS_DOWN:
|
|
return "Press Down";
|
|
case WUPS_BUTTON_COMBO_COMBO_TYPE_PRESS_DOWN_OBSERVER:
|
|
return "Press Down (Observer)";
|
|
}
|
|
return "invalid";
|
|
}
|
|
|
|
std::string toString(WUPSButtonCombo_ComboStatus type) {
|
|
switch (type) {
|
|
case WUPS_BUTTON_COMBO_COMBO_STATUS_INVALID_STATUS:
|
|
return "Invalid";
|
|
case WUPS_BUTTON_COMBO_COMBO_STATUS_VALID:
|
|
return "Valid";
|
|
case WUPS_BUTTON_COMBO_COMBO_STATUS_CONFLICT:
|
|
return "Conflict";
|
|
}
|
|
return "Invalid";
|
|
}
|
|
|
|
|
|
std::string toString(const function_replacement_library_type_t type) {
|
|
switch (type) {
|
|
case LIBRARY_AVM:
|
|
return "AVM";
|
|
case LIBRARY_CAMERA:
|
|
return "CAMERA";
|
|
case LIBRARY_COREINIT:
|
|
return "COREINIT";
|
|
case LIBRARY_DC:
|
|
return "DC";
|
|
case LIBRARY_DMAE:
|
|
return "DMAE";
|
|
case LIBRARY_DRMAPP:
|
|
return "DRMAPP";
|
|
case LIBRARY_ERREULA:
|
|
return "ERREULA";
|
|
case LIBRARY_GX2:
|
|
return "GX2";
|
|
case LIBRARY_H264:
|
|
return "H264";
|
|
case LIBRARY_LZMA920:
|
|
return "LZMA920";
|
|
case LIBRARY_MIC:
|
|
return "MIC";
|
|
case LIBRARY_NFC:
|
|
return "NFC";
|
|
case LIBRARY_NIO_PROF:
|
|
return "NIO_PROF";
|
|
case LIBRARY_NLIBCURL:
|
|
return "NLIBCURL";
|
|
case LIBRARY_NLIBNSS:
|
|
return "NLIBNSS";
|
|
case LIBRARY_NLIBNSS2:
|
|
return "NLIBNSS2";
|
|
case LIBRARY_NN_AC:
|
|
return "NN_AC";
|
|
case LIBRARY_NN_ACP:
|
|
return "NN_ACP";
|
|
case LIBRARY_NN_ACT:
|
|
return "NN_ACT";
|
|
case LIBRARY_NN_AOC:
|
|
return "NN_AOC";
|
|
case LIBRARY_NN_BOSS:
|
|
return "NN_BOSS";
|
|
case LIBRARY_NN_CCR:
|
|
return "NN_CCR";
|
|
case LIBRARY_NN_CMPT:
|
|
return "NN_CMPT";
|
|
case LIBRARY_NN_DLP:
|
|
return "NN_DLP";
|
|
case LIBRARY_NN_EC:
|
|
return "NN_EC";
|
|
case LIBRARY_NN_FP:
|
|
return "NN_FP";
|
|
case LIBRARY_NN_HAI:
|
|
return "NN_HAI";
|
|
case LIBRARY_NN_HPAD:
|
|
return "NN_HPAD";
|
|
case LIBRARY_NN_IDBE:
|
|
return "NN_IDBE";
|
|
case LIBRARY_NN_NDM:
|
|
return "NN_NDM";
|
|
case LIBRARY_NN_NETS2:
|
|
return "NN_NETS2";
|
|
case LIBRARY_NN_NFP:
|
|
return "NN_NFP";
|
|
case LIBRARY_NN_NIM:
|
|
return "NN_NIM";
|
|
case LIBRARY_NN_OLV:
|
|
return "NN_OLV";
|
|
case LIBRARY_NN_PDM:
|
|
return "NN_PDM";
|
|
case LIBRARY_NN_SAVE:
|
|
return "NN_SAVE";
|
|
case LIBRARY_NN_SL:
|
|
return "NN_SL";
|
|
case LIBRARY_NN_SPM:
|
|
return "NN_SPM";
|
|
case LIBRARY_NN_TEMP:
|
|
return "NN_TEMP";
|
|
case LIBRARY_NN_UDS:
|
|
return "NN_UDS";
|
|
case LIBRARY_NN_VCTL:
|
|
return "NN_VCTL";
|
|
case LIBRARY_NSYSCCR:
|
|
return "NSYSCCR";
|
|
case LIBRARY_NSYSHID:
|
|
return "NSYSHID";
|
|
case LIBRARY_NSYSKBD:
|
|
return "NSYSKBD";
|
|
case LIBRARY_NSYSNET:
|
|
return "NSYSNET";
|
|
case LIBRARY_NSYSUHS:
|
|
return "NSYSUHS";
|
|
case LIBRARY_NSYSUVD:
|
|
return "NSYSUVD";
|
|
case LIBRARY_NTAG:
|
|
return "NTAG";
|
|
case LIBRARY_PADSCORE:
|
|
return "PADSCORE";
|
|
case LIBRARY_PROC_UI:
|
|
return "PROC_UI";
|
|
case LIBRARY_SND_CORE:
|
|
return "SND_CORE";
|
|
case LIBRARY_SND_USER:
|
|
return "SND_USER";
|
|
case LIBRARY_SNDCORE2:
|
|
return "SNDCORE2";
|
|
case LIBRARY_SNDUSER2:
|
|
return "SNDUSER2";
|
|
case LIBRARY_SWKBD:
|
|
return "SWKBD";
|
|
case LIBRARY_SYSAPP:
|
|
return "SYSAPP";
|
|
case LIBRARY_TCL:
|
|
return "TCL";
|
|
case LIBRARY_TVE:
|
|
return "TVE";
|
|
case LIBRARY_UAC:
|
|
return "UAC";
|
|
case LIBRARY_UAC_RPL:
|
|
return "UAC_RPL";
|
|
case LIBRARY_USB_MIC:
|
|
return "USB_MIC";
|
|
case LIBRARY_UVC:
|
|
return "UVC";
|
|
case LIBRARY_UVD:
|
|
return "UVD";
|
|
case LIBRARY_VPAD:
|
|
return "VPAD";
|
|
case LIBRARY_VPADBASE:
|
|
return "VPADBASE";
|
|
case LIBRARY_ZLIB125:
|
|
return "ZLIB125";
|
|
case LIBRARY_OTHER:
|
|
return "OTHER";
|
|
}
|
|
return "OTHER";
|
|
}
|
|
|
|
const char *getButtonChar(const WUPSButtonCombo_Buttons value) {
|
|
std::string combo;
|
|
if (value & WUPS_BUTTON_COMBO_BUTTON_A) {
|
|
return "A";
|
|
}
|
|
if (value & WUPS_BUTTON_COMBO_BUTTON_B) {
|
|
return "B";
|
|
}
|
|
if (value & WUPS_BUTTON_COMBO_BUTTON_X) {
|
|
return "X";
|
|
}
|
|
if (value & WUPS_BUTTON_COMBO_BUTTON_Y) {
|
|
return "Y";
|
|
}
|
|
if (value & WUPS_BUTTON_COMBO_BUTTON_L) {
|
|
return "L";
|
|
}
|
|
if (value & WUPS_BUTTON_COMBO_BUTTON_R) {
|
|
return "R";
|
|
}
|
|
if (value & WUPS_BUTTON_COMBO_BUTTON_ZL) {
|
|
return "ZL";
|
|
}
|
|
if (value & WUPS_BUTTON_COMBO_BUTTON_ZR) {
|
|
return "ZR";
|
|
}
|
|
if (value & WUPS_BUTTON_COMBO_BUTTON_UP) {
|
|
return "UP";
|
|
}
|
|
if (value & WUPS_BUTTON_COMBO_BUTTON_DOWN) {
|
|
return "DOWN";
|
|
}
|
|
if (value & WUPS_BUTTON_COMBO_BUTTON_LEFT) {
|
|
return "LEFT";
|
|
}
|
|
if (value & WUPS_BUTTON_COMBO_BUTTON_RIGHT) {
|
|
return "RIGHT";
|
|
}
|
|
if (value & WUPS_BUTTON_COMBO_BUTTON_STICK_L) {
|
|
return "STICK-L";
|
|
}
|
|
if (value & WUPS_BUTTON_COMBO_BUTTON_STICK_R) {
|
|
return "STICK-R";
|
|
}
|
|
if (value & WUPS_BUTTON_COMBO_BUTTON_PLUS) {
|
|
return "PLUS";
|
|
}
|
|
if (value & WUPS_BUTTON_COMBO_BUTTON_MINUS) {
|
|
return "MINUS";
|
|
}
|
|
if (value & WUPS_BUTTON_COMBO_BUTTON_TV) {
|
|
return "TV";
|
|
}
|
|
if (value & WUPS_BUTTON_COMBO_BUTTON_RESERVED_BIT) {
|
|
return "RESERVED-BIT";
|
|
}
|
|
if (value & WUPS_BUTTON_COMBO_BUTTON_1) {
|
|
return "1";
|
|
}
|
|
if (value & WUPS_BUTTON_COMBO_BUTTON_2) {
|
|
return "2";
|
|
}
|
|
if (value & WUPS_BUTTON_COMBO_BUTTON_C) {
|
|
return "C";
|
|
}
|
|
if (value & WUPS_BUTTON_COMBO_BUTTON_Z) {
|
|
return "Z";
|
|
}
|
|
return "";
|
|
}
|
|
|
|
std::string getComboAsString(const uint32_t value) {
|
|
char comboString[60] = {};
|
|
|
|
for (uint32_t i = 0; i < 32; i++) {
|
|
uint32_t bitMask = 1 << i;
|
|
if (value & bitMask) {
|
|
auto val = getButtonChar(static_cast<WUPSButtonCombo_Buttons>(bitMask));
|
|
if (val[0] != '\0') {
|
|
strcat(comboString, val);
|
|
strcat(comboString, "+");
|
|
}
|
|
}
|
|
}
|
|
std::string res(comboString);
|
|
if (res.ends_with("+")) {
|
|
res.pop_back();
|
|
}
|
|
return res;
|
|
}
|
|
|
|
std::string getMaskAsString(WUPSButtonCombo_ControllerTypes controller_mask) {
|
|
if (controller_mask == WUPS_BUTTON_COMBO_CONTROLLER_NONE) {
|
|
return "NONE";
|
|
}
|
|
if (controller_mask == WUPS_BUTTON_COMBO_CONTROLLER_ALL) {
|
|
return "ALL";
|
|
}
|
|
// Optional: Check strictly for full groups if you prefer that over listing individual bits
|
|
if (controller_mask == WUPS_BUTTON_COMBO_CONTROLLER_VPAD) {
|
|
return "VPAD (All)";
|
|
}
|
|
if (controller_mask == WUPS_BUTTON_COMBO_CONTROLLER_WPAD) {
|
|
return "WPAD (All)";
|
|
}
|
|
std::vector<std::string> parts;
|
|
|
|
// VPADs
|
|
if (controller_mask & WUPS_BUTTON_COMBO_CONTROLLER_VPAD_0) parts.emplace_back("VPAD_0");
|
|
if (controller_mask & WUPS_BUTTON_COMBO_CONTROLLER_VPAD_1) parts.emplace_back("VPAD_1");
|
|
|
|
// WPADs
|
|
if (controller_mask & WUPS_BUTTON_COMBO_CONTROLLER_WPAD_0) parts.emplace_back("WPAD_0");
|
|
if (controller_mask & WUPS_BUTTON_COMBO_CONTROLLER_WPAD_1) parts.emplace_back("WPAD_1");
|
|
if (controller_mask & WUPS_BUTTON_COMBO_CONTROLLER_WPAD_2) parts.emplace_back("WPAD_2");
|
|
if (controller_mask & WUPS_BUTTON_COMBO_CONTROLLER_WPAD_3) parts.emplace_back("WPAD_3");
|
|
if (controller_mask & WUPS_BUTTON_COMBO_CONTROLLER_WPAD_4) parts.emplace_back("WPAD_4");
|
|
if (controller_mask & WUPS_BUTTON_COMBO_CONTROLLER_WPAD_5) parts.emplace_back("WPAD_5");
|
|
if (controller_mask & WUPS_BUTTON_COMBO_CONTROLLER_WPAD_6) parts.emplace_back("WPAD_6");
|
|
|
|
|
|
if (parts.empty()) {
|
|
return "UNKNOWN";
|
|
}
|
|
|
|
std::string result;
|
|
for (size_t i = 0; i < parts.size(); ++i) {
|
|
if (i > 0) {
|
|
result += " | ";
|
|
}
|
|
result += parts[i];
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
bool isHoldCombo(WUPSButtonCombo_ComboType type) {
|
|
switch (type) {
|
|
case WUPS_BUTTON_COMBO_COMBO_TYPE_HOLD:
|
|
case WUPS_BUTTON_COMBO_COMBO_TYPE_HOLD_OBSERVER:
|
|
return true;
|
|
case WUPS_BUTTON_COMBO_COMBO_TYPE_INVALID:
|
|
case WUPS_BUTTON_COMBO_COMBO_TYPE_PRESS_DOWN:
|
|
case WUPS_BUTTON_COMBO_COMBO_TYPE_PRESS_DOWN_OBSERVER:
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
} // namespace
|
|
namespace ShellCommands {
|
|
namespace {
|
|
class ConsoleTable {
|
|
public:
|
|
enum Alignment { LEFT,
|
|
RIGHT };
|
|
|
|
void AddColumn(const std::string &title, const Alignment align = LEFT) {
|
|
mCols.push_back({title, align, title.length()});
|
|
}
|
|
|
|
void AddRow(const std::vector<std::string> &rowData) {
|
|
if (rowData.size() != mCols.size()) return;
|
|
mRows.push_back(rowData);
|
|
updateWidths(rowData);
|
|
}
|
|
|
|
void AddFooter(const std::vector<std::string> &footerData) {
|
|
if (footerData.size() != mCols.size()) return;
|
|
mFooter = footerData;
|
|
updateWidths(footerData);
|
|
}
|
|
|
|
void Print() {
|
|
OSReport("\n");
|
|
PrintSeparator();
|
|
|
|
OSReport("|");
|
|
for (const auto &[title, align, width] : mCols) printCell(title, width, align);
|
|
OSReport("\n");
|
|
|
|
PrintSeparator();
|
|
|
|
for (const auto &row : mRows) {
|
|
OSReport("|");
|
|
for (size_t i = 0; i < row.size(); ++i) printCell(row[i], mCols[i].width, mCols[i].align);
|
|
OSReport("\n");
|
|
}
|
|
|
|
if (!mFooter.empty()) {
|
|
PrintSeparator();
|
|
OSReport("|");
|
|
for (size_t i = 0; i < mFooter.size(); ++i) printCell(mFooter[i], mCols[i].width, mCols[i].align);
|
|
OSReport("\n");
|
|
}
|
|
|
|
size_t totalWidth = 1;
|
|
for (const auto &col : mCols) {
|
|
totalWidth += col.width + 3;
|
|
}
|
|
|
|
std::string border(totalWidth, '-');
|
|
OSReport("%s\n", border.c_str());
|
|
}
|
|
|
|
private:
|
|
void updateWidths(const std::vector<std::string> &data) {
|
|
for (size_t i = 0; i < mCols.size(); ++i) {
|
|
if (data[i].length() > mCols[i].width) {
|
|
mCols[i].width = data[i].length();
|
|
}
|
|
}
|
|
}
|
|
|
|
void PrintSeparator() const {
|
|
OSReport("|");
|
|
for (const auto &col : mCols) {
|
|
// Separator is width + 2 spaces padding
|
|
std::string line(col.width + 2, '-');
|
|
OSReport("%s|", line.c_str());
|
|
}
|
|
OSReport("\n");
|
|
}
|
|
|
|
static void printCell(const std::string &text, const size_t width, const Alignment align) {
|
|
if (align == LEFT) OSReport(" %-*s |", static_cast<int>(width), text.c_str());
|
|
else
|
|
OSReport(" %*s |", static_cast<int>(width), text.c_str());
|
|
}
|
|
|
|
struct Column {
|
|
std::string title;
|
|
Alignment align;
|
|
size_t width;
|
|
};
|
|
|
|
std::vector<Column> mCols;
|
|
std::vector<std::vector<std::string>> mRows;
|
|
std::vector<std::string> mFooter;
|
|
};
|
|
} // namespace
|
|
|
|
std::string BytesToHumanReadable(uint32_t bytes) {
|
|
char buffer[32];
|
|
snprintf(buffer, sizeof(buffer), "%.2f KiB", bytes / 1024.0f);
|
|
return std::string(buffer);
|
|
}
|
|
|
|
void PrintHeapUsage() {
|
|
ConsoleTable table;
|
|
|
|
table.AddColumn("Plugin name", ConsoleTable::LEFT);
|
|
table.AddColumn("Current usage", ConsoleTable::RIGHT);
|
|
table.AddColumn("Peak usage", ConsoleTable::RIGHT);
|
|
table.AddColumn("Current allocations", ConsoleTable::RIGHT);
|
|
table.AddColumn("Total allocations", ConsoleTable::RIGHT);
|
|
table.AddColumn("Total frees", ConsoleTable::RIGHT);
|
|
|
|
uint32_t totalCurrentBytes = 0;
|
|
uint32_t totalPeakBytes = 0;
|
|
uint32_t totalChunks = 0;
|
|
|
|
for (const auto &plugin : gLoadedPlugins) {
|
|
if (!plugin.isLinkedAndLoaded() || !plugin.isUsingTrackingPluginHeapMemoryAllocator()) {
|
|
continue;
|
|
}
|
|
|
|
const auto tracking = plugin.getTrackingMemoryAllocator();
|
|
if (!tracking) { continue; }
|
|
|
|
const auto stats = tracking->GetHeapMemoryUsageSnapshot();
|
|
if (!stats) { continue; }
|
|
|
|
auto activeChunks = stats->allocationMap.size();
|
|
|
|
table.AddRow({stats->pluginName,
|
|
BytesToHumanReadable(stats->currentAllocated),
|
|
BytesToHumanReadable(stats->peakAllocated),
|
|
std::to_string(activeChunks),
|
|
std::to_string(stats->allocCount),
|
|
std::to_string(stats->freeCount)});
|
|
|
|
// Accumulate Totals
|
|
totalCurrentBytes += stats->currentAllocated;
|
|
totalPeakBytes += stats->peakAllocated;
|
|
totalChunks += activeChunks;
|
|
}
|
|
|
|
// Add the Footer Row
|
|
table.AddFooter({"TOTAL (tracked plugins)",
|
|
BytesToHumanReadable(totalCurrentBytes),
|
|
BytesToHumanReadable(totalPeakBytes),
|
|
std::to_string(totalChunks),
|
|
"-",
|
|
"-"});
|
|
|
|
table.Print();
|
|
}
|
|
|
|
void ListPlugins(int argc, char **argv) {
|
|
bool showAll = false;
|
|
if (argc > 1 && (std::string_view(argv[1]) == "-a" || std::string_view(argv[1]) == "--all")) {
|
|
showAll = true;
|
|
}
|
|
|
|
ConsoleTable table;
|
|
|
|
table.AddColumn("Index", ConsoleTable::LEFT);
|
|
table.AddColumn("Name", ConsoleTable::LEFT);
|
|
table.AddColumn("Author", ConsoleTable::LEFT);
|
|
table.AddColumn("Version", ConsoleTable::LEFT);
|
|
if (showAll) {
|
|
table.AddColumn("Active", ConsoleTable::LEFT);
|
|
}
|
|
table.AddColumn("API", ConsoleTable::LEFT);
|
|
table.AddColumn("Memory footprint", ConsoleTable::RIGHT);
|
|
table.AddColumn("Heap usage", ConsoleTable::RIGHT);
|
|
uint32_t totalSizeOther = 0;
|
|
uint32_t id = 0;
|
|
for (const auto &plugin : gLoadedPlugins) {
|
|
if (!showAll && !plugin.isLinkedAndLoaded()) {
|
|
totalSizeOther += plugin.getMemoryFootprint();
|
|
id++;
|
|
continue;
|
|
}
|
|
|
|
auto &meta = plugin.getMetaInformation();
|
|
|
|
std::string heapUsage = "unknown";
|
|
if (const auto tracking = plugin.getTrackingMemoryAllocator()) {
|
|
uint32_t heapUsageSize = 0;
|
|
if (const auto stats = tracking->GetHeapMemoryUsageSnapshot()) {
|
|
heapUsageSize = stats->currentAllocated;
|
|
}
|
|
heapUsage = BytesToHumanReadable(heapUsageSize);
|
|
}
|
|
|
|
std::vector<std::string> rowData;
|
|
rowData.emplace_back(std::to_string(id));
|
|
rowData.emplace_back(meta.getName());
|
|
rowData.emplace_back(meta.getAuthor());
|
|
rowData.emplace_back(meta.getVersion());
|
|
if (showAll) {
|
|
rowData.emplace_back(plugin.isLinkedAndLoaded() ? "Yes" : "No");
|
|
}
|
|
rowData.emplace_back(meta.getWUPSVersion().toString());
|
|
rowData.emplace_back("~ " + BytesToHumanReadable(plugin.getMemoryFootprint()));
|
|
rowData.emplace_back(heapUsage);
|
|
|
|
table.AddRow(rowData);
|
|
id++;
|
|
}
|
|
|
|
if (totalSizeOther > 0 && !showAll) {
|
|
std::vector<std::string> rowData;
|
|
rowData.emplace_back("Inactive Plugins");
|
|
rowData.emplace_back("-");
|
|
rowData.emplace_back("-");
|
|
|
|
rowData.emplace_back("-");
|
|
rowData.emplace_back("~ " + BytesToHumanReadable(totalSizeOther));
|
|
rowData.emplace_back("-");
|
|
|
|
table.AddFooter(rowData);
|
|
}
|
|
|
|
table.Print();
|
|
}
|
|
|
|
void PluginDetails(std::optional<uint32_t> idOpt) {
|
|
uint32_t id = 0;
|
|
for (const auto &plugin : gLoadedPlugins) {
|
|
if (idOpt) {
|
|
if (*idOpt != id) {
|
|
id++;
|
|
continue;
|
|
}
|
|
}
|
|
auto &meta = plugin.getMetaInformation();
|
|
OSReport("\n");
|
|
OSReport("Index: %d\n", id);
|
|
OSReport("Name: %s\n", meta.getName().c_str());
|
|
OSReport("Description: %s\n", meta.getDescription().c_str());
|
|
OSReport("Author: %s\n", meta.getAuthor().c_str());
|
|
OSReport("Version: %s\n", meta.getVersion().c_str());
|
|
OSReport("Build date: %s\n", meta.getBuildTimestamp().c_str());
|
|
if (!meta.getStorageId().empty()) {
|
|
OSReport("Storage Id: %s\n", meta.getStorageId().c_str());
|
|
}
|
|
OSReport("Active: %s\n", plugin.isLinkedAndLoaded() ? "Yes" : "No");
|
|
OSReport("API: %s\n", meta.getWUPSVersion().toString().c_str());
|
|
|
|
const auto memoryFootprint = plugin.getMemoryFootprint();
|
|
const auto pluginSize = plugin.getPluginDataCopy()->getBuffer().size_bytes();
|
|
size_t textSize = 0;
|
|
size_t dataSize = 0;
|
|
|
|
OSReport("Memory footprint: ~%s\n", BytesToHumanReadable(memoryFootprint).c_str());
|
|
OSReport("\t- .wps: ~%s\n", BytesToHumanReadable(pluginSize).c_str());
|
|
if (plugin.isLinkedAndLoaded()) {
|
|
textSize = plugin.getPluginLinkInformation().getTextMemory().size();
|
|
dataSize = plugin.getPluginLinkInformation().getDataMemory().size();
|
|
OSReport("\t- CODE: ~%s\n", BytesToHumanReadable(textSize).c_str());
|
|
OSReport("\t- DATA: ~%s\n", BytesToHumanReadable(dataSize).c_str());
|
|
}
|
|
const auto otherSize = memoryFootprint - pluginSize - textSize - dataSize;
|
|
OSReport("\t- Other: ~%s\n", BytesToHumanReadable(otherSize).c_str());
|
|
OSReport("\n");
|
|
if (plugin.isLinkedAndLoaded()) {
|
|
const auto §ionInfoList = plugin.getPluginLinkInformation().getSectionInfoList();
|
|
OSReport("Sections: %d\n", sectionInfoList.size());
|
|
for (const auto §ionInfo : sectionInfoList) {
|
|
OSReport("\t- 0x%08X - 0x%08X %-15s %-11s\n", sectionInfo.second.getAddress(), sectionInfo.second.getAddress() + sectionInfo.second.getSize(), sectionInfo.first.c_str(), BytesToHumanReadable(sectionInfo.second.getSize()).c_str());
|
|
}
|
|
OSReport("\n");
|
|
|
|
const auto &hookList = plugin.getPluginLinkInformation().getHookDataList();
|
|
OSReport("WUPS Hooks: %d\n", hookList.size());
|
|
for (const auto &hook : hookList) {
|
|
OSReport("\t- %p - %s\n", hook.getFunctionPointer(), hookNameToString(hook.getType()).c_str());
|
|
}
|
|
OSReport("\n");
|
|
const auto &buttonCombos = plugin.GetButtonComboData();
|
|
OSReport("Button combos: %d\n", buttonCombos.size());
|
|
for (const auto &combo : buttonCombos) {
|
|
OSReport("\t- \"%s\" \n", combo.label.c_str());
|
|
OSReport("\t\tStatus: %s\n", toString(combo.status).c_str());
|
|
OSReport("\t\tCallback: %p (%s)\n", combo.callbackOptions.callback, combo.callbackOptions.callback != nullptr ? getModuleAndSymbolName(reinterpret_cast<uint32_t>(combo.callbackOptions.callback)).c_str() : "");
|
|
OSReport("\t\tContext: %p\n", combo.callbackOptions.context);
|
|
OSReport("\t\tType: %s\n", toString(combo.buttonComboOptions.type).c_str());
|
|
if (isHoldCombo(combo.buttonComboOptions.type)) {
|
|
OSReport("\t\tHold duration: %d\n", combo.buttonComboOptions.optionalHoldForXMs);
|
|
}
|
|
OSReport("\t\tCombo: %s\n", getComboAsString(combo.buttonComboOptions.basicCombo.combo).c_str());
|
|
OSReport("\t\tController Mask: %s\n", getMaskAsString(combo.buttonComboOptions.basicCombo.controllerMask).c_str());
|
|
}
|
|
OSReport("\n");
|
|
const auto &functionPatches = plugin.getPluginLinkInformation().getFunctionDataList();
|
|
OSReport("Function patches: %d\n", functionPatches.size());
|
|
for (const auto &function : functionPatches) {
|
|
if (function.getPhysicalAddress() != nullptr) {
|
|
OSReport("\t- Hook: %p - PA: %p VA: %p\n", function.getReplaceAddress(), function.getPhysicalAddress(), function.getVirtualAddress());
|
|
} else {
|
|
OSReport("\t- Hook: %p - %-9s - %s\n", function.getReplaceAddress(), toString(function.getLibrary()).c_str(), function.getName().c_str());
|
|
}
|
|
}
|
|
|
|
OSReport("\n");
|
|
OSReport("Heap usage:\n");
|
|
if (const auto tracking = plugin.getTrackingMemoryAllocator(); tracking != nullptr) {
|
|
if (const auto stats = tracking->GetHeapMemoryUsageSnapshot(); stats) {
|
|
OSReport("\t- Currently allocated: %s\n", BytesToHumanReadable(stats->currentAllocated).c_str());
|
|
OSReport("\t- Peak allocated: %s\n", BytesToHumanReadable(stats->peakAllocated).c_str());
|
|
OSReport("\t- Current allocations: %d\n", stats->allocationMap.size());
|
|
OSReport("\t- Total allocations: %d\n", stats->allocCount);
|
|
OSReport("\t- Total frees: %d\n", stats->freeCount);
|
|
}
|
|
} else {
|
|
OSReport("\t Not tracked.\n");
|
|
}
|
|
}
|
|
|
|
OSReport("\n=================\n");
|
|
|
|
id++;
|
|
if (idOpt) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static std::unique_ptr<IOPShellModule::CommandGroup> sPluginsGroup;
|
|
void InitPluginsCommandGroup() {
|
|
// Must be in memory while commands are active
|
|
sPluginsGroup = std::make_unique<IOPShellModule::CommandGroup>("plugins", "Manage aroma plugins");
|
|
if (const auto res = sPluginsGroup->RegisterGroup(); res != IOPSHELL_MODULE_ERROR_SUCCESS) {
|
|
DEBUG_FUNCTION_LINE_WARN("Failed to register \"aroma plugins\" command: %s", IOPShellModule::GetErrorString(res));
|
|
}
|
|
|
|
if (const auto res = sPluginsGroup->AddCommand("heap_usage", PrintHeapUsage, "Show current heap usage for tracked plugins"); res != IOPSHELL_MODULE_ERROR_SUCCESS) {
|
|
DEBUG_FUNCTION_LINE_WARN("Failed to create \"aroma plugins heap_usage\" command: %s", IOPShellModule::GetErrorString(res));
|
|
}
|
|
if (const auto res = sPluginsGroup->AddRawCommand("list", ListPlugins, "Lists active plugins", "Usage: \"list -a\" to list all plugins"); res != IOPSHELL_MODULE_ERROR_SUCCESS) {
|
|
DEBUG_FUNCTION_LINE_WARN("Failed to create \"aroma plugins list\" command: %s", IOPShellModule::GetErrorString(res));
|
|
}
|
|
if (auto res = sPluginsGroup->AddCommand("details", PluginDetails, "Shows details for plugins"); res != IOPSHELL_MODULE_ERROR_SUCCESS) {
|
|
DEBUG_FUNCTION_LINE_WARN("Failed to create \"aroma plugins details\" command: %s", IOPShellModule::GetErrorString(res));
|
|
} else {
|
|
if (res = sPluginsGroup->AddAlias("details", "show"); res != IOPSHELL_MODULE_ERROR_SUCCESS) {
|
|
DEBUG_FUNCTION_LINE_WARN("Failed to create \"aroma plugins details\" alias \"aroma plugins show\": %s", IOPShellModule::GetErrorString(res));
|
|
}
|
|
}
|
|
|
|
if (const auto res = sPluginsGroup->RegisterGroup(); res != IOPSHELL_MODULE_ERROR_SUCCESS) {
|
|
DEBUG_FUNCTION_LINE_WARN("Failed to register \"aroma plugins\" command: %s", IOPShellModule::GetErrorString(res));
|
|
}
|
|
}
|
|
|
|
void Init() {
|
|
InitPluginsCommandGroup();
|
|
}
|
|
} // namespace ShellCommands
|