CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/Core/Debugger/SymbolMap.cpp
Views: 1401
// Copyright (c) 2012- PPSSPP Project.12// This program is free software: you can redistribute it and/or modify3// it under the terms of the GNU General Public License as published by4// the Free Software Foundation, version 2.0 or later versions.56// This program is distributed in the hope that it will be useful,7// but WITHOUT ANY WARRANTY; without even the implied warranty of8// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the9// GNU General Public License 2.0 for more details.1011// A copy of the GPL 2.0 should have been included with the program.12// If not, see http://www.gnu.org/licenses/1314// Official git repository and contact information can be found at15// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.1617// These functions tends to be slow in debug mode.18// Comment this out if debugging the symbol map itself.19#if defined(_MSC_VER) && defined(_DEBUG)20#pragma optimize("gty", on)21#endif2223#include "ppsspp_config.h"24#ifdef _WIN3225#include "Common/CommonWindows.h"26#include <WindowsX.h>27#else28#include <unistd.h>29#endif3031#include <algorithm>32#include <memory>33#ifndef NO_ARMIPS34#include <string_view>35#endif36#include <unordered_map>3738#include "zlib.h"3940#include "Common/CommonTypes.h"41#include "Common/Data/Encoding/Utf8.h"42#include "Common/Log.h"43#include "Common/File/FileUtil.h"44#include "Common/StringUtils.h"45#include "Core/MemMap.h"46#include "Core/Debugger/SymbolMap.h"4748#ifndef NO_ARMIPS49#include "ext/armips/Core/Assembler.h"50#else51struct Identifier {52explicit Identifier() {}53explicit Identifier(const std::string &s) {}54};5556struct LabelDefinition {57Identifier name;58int64_t value;59};60#endif6162SymbolMap *g_symbolMap;6364void SymbolMap::SortSymbols() {65std::lock_guard<std::recursive_mutex> guard(lock_);6667AssignFunctionIndices();68}6970void SymbolMap::Clear() {71std::lock_guard<std::recursive_mutex> guard(lock_);72functions.clear();73labels.clear();74data.clear();75activeFunctions.clear();76activeLabels.clear();77activeData.clear();78activeModuleEnds.clear();79modules.clear();80activeNeedUpdate_ = false;81}8283bool SymbolMap::LoadSymbolMap(const Path &filename) {84Clear(); // let's not recurse the lock8586std::lock_guard<std::recursive_mutex> guard(lock_);8788// TODO(scoped): Use gzdopen instead.8990#if defined(_WIN32) && defined(UNICODE)91gzFile f = gzopen_w(filename.ToWString().c_str(), "r");92#else93gzFile f = gzopen(filename.c_str(), "r");94#endif9596if (f == Z_NULL)97return false;9899//char temp[256];100//fgets(temp,255,f); //.text section layout101//fgets(temp,255,f); // Starting Virtual102//fgets(temp,255,f); // address Size address103//fgets(temp,255,f); // -----------------------104105bool started = false;106bool hasModules = false;107108while (!gzeof(f)) {109char line[512], temp[256] = {0};110char *p = gzgets(f, line, 512);111if (p == NULL)112break;113114// Chop any newlines off.115for (size_t i = strlen(line) - 1; i > 0; i--) {116if (line[i] == '\r' || line[i] == '\n') {117line[i] = '\0';118}119}120121if (strlen(line) < 4 || sscanf(line, "%255s", temp) != 1)122continue;123124if (strcmp(temp,"UNUSED")==0) continue;125if (strcmp(temp,".text")==0) {started=true;continue;};126if (strcmp(temp,".init")==0) {started=true;continue;};127if (strcmp(temp,"Starting")==0) continue;128if (strcmp(temp,"extab")==0) continue;129if (strcmp(temp,".ctors")==0) break;130if (strcmp(temp,".dtors")==0) break;131if (strcmp(temp,".rodata")==0) continue;132if (strcmp(temp,".data")==0) continue;133if (strcmp(temp,".sbss")==0) continue;134if (strcmp(temp,".sdata")==0) continue;135if (strcmp(temp,".sdata2")==0) continue;136if (strcmp(temp,"address")==0) continue;137if (strcmp(temp,"-----------------------")==0) continue;138if (strcmp(temp,".sbss2")==0) break;139if (temp[1]==']') continue;140141if (!started) continue;142143u32 address = -1, size = 0, vaddress = -1;144int moduleIndex = 0;145int typeInt = ST_NONE;146SymbolType type;147char name[128] = {0};148149if (sscanf(line, ".module %x %08x %08x %127c", (unsigned int *)&moduleIndex, &address, &size, name) >= 3) {150// Found a module definition.151ModuleEntry mod;152mod.index = moduleIndex;153strcpy(mod.name, name);154mod.start = address;155mod.size = size;156modules.push_back(mod);157hasModules = true;158continue;159}160161int matched = sscanf(line, "%08x %08x %x %i %127c", &address, &size, &vaddress, &typeInt, name);162if (matched < 1)163continue;164type = (SymbolType) typeInt;165if (!hasModules) {166if (!Memory::IsValidAddress(vaddress)) {167ERROR_LOG(Log::Loader, "Invalid address in symbol file: %08x (%s)", vaddress, name);168continue;169}170} else {171// The 3rd field is now used for the module index.172moduleIndex = vaddress;173vaddress = GetModuleAbsoluteAddr(address, moduleIndex);174if (!Memory::IsValidAddress(vaddress)) {175ERROR_LOG(Log::Loader, "Invalid address in symbol file: %08x (%s)", vaddress, name);176continue;177}178}179180if (type == ST_DATA && size == 0)181size = 4;182183// Ignore syscalls, will be recognized from stubs.184// Note: it's still useful to save these for grepping and importing into other tools.185if (strncmp(name, "zz_sce", 6) == 0)186continue;187// Also ignore unresolved imports, which will similarly be replaced.188if (strncmp(name, "zz_[UNK", 7) == 0)189continue;190191if (!strcmp(name, ".text") || !strcmp(name, ".init") || strlen(name) <= 1) {192193} else {194switch (type)195{196case ST_FUNCTION:197AddFunction(name, vaddress, size, moduleIndex);198break;199case ST_DATA:200AddData(vaddress,size,DATATYPE_BYTE, moduleIndex);201if (name[0] != 0)202AddLabel(name, vaddress, moduleIndex);203break;204case ST_NONE:205case ST_ALL:206// Shouldn't be possible.207break;208}209}210}211gzclose(f);212SortSymbols();213return started;214}215216bool SymbolMap::SaveSymbolMap(const Path &filename) const {217std::lock_guard<std::recursive_mutex> guard(lock_);218219// Don't bother writing a blank file.220if (!File::Exists(filename) && functions.empty() && data.empty()) {221return true;222}223224// TODO(scoped): Use gzdopen225#if defined(_WIN32) && defined(UNICODE)226gzFile f = gzopen_w(filename.ToWString().c_str(), "w9");227#else228gzFile f = gzopen(filename.c_str(), "w9");229#endif230231if (f == Z_NULL)232return false;233234gzprintf(f, ".text\n");235236for (auto it = modules.begin(), end = modules.end(); it != end; ++it) {237const ModuleEntry &mod = *it;238gzprintf(f, ".module %x %08x %08x %s\n", mod.index, mod.start, mod.size, mod.name);239}240241for (auto it = functions.begin(), end = functions.end(); it != end; ++it) {242const FunctionEntry& e = it->second;243gzprintf(f, "%08x %08x %x %i %s\n", e.start, e.size, e.module, ST_FUNCTION, GetLabelNameRel(e.start, e.module));244}245246for (auto it = data.begin(), end = data.end(); it != end; ++it) {247const DataEntry& e = it->second;248gzprintf(f, "%08x %08x %x %i %s\n", e.start, e.size, e.module, ST_DATA, GetLabelNameRel(e.start, e.module));249}250gzclose(f);251return true;252}253254bool SymbolMap::LoadNocashSym(const Path &filename) {255std::lock_guard<std::recursive_mutex> guard(lock_);256FILE *f = File::OpenCFile(filename, "r");257if (!f)258return false;259260while (!feof(f)) {261char line[256], value[256] = {0};262char *p = fgets(line, 256, f);263if (p == NULL)264break;265266u32 address;267if (sscanf(line, "%08X %255s", &address, value) != 2)268continue;269if (address == 0 && strcmp(value, "0") == 0)270continue;271272if (value[0] == '.') {273// data directives274char* s = strchr(value, ':');275if (s != NULL) {276*s = 0;277278u32 size = 0;279if (sscanf(s + 1, "%04X", &size) != 1)280continue;281282if (strcasecmp(value, ".byt") == 0) {283AddData(address, size, DATATYPE_BYTE, 0);284} else if (strcasecmp(value, ".wrd") == 0) {285AddData(address, size, DATATYPE_HALFWORD, 0);286} else if (strcasecmp(value, ".dbl") == 0) {287AddData(address, size, DATATYPE_WORD, 0);288} else if (strcasecmp(value, ".asc") == 0) {289AddData(address, size, DATATYPE_ASCII, 0);290}291}292} else { // labels293unsigned int size = 1;294char* seperator = strchr(value, ',');295if (seperator != NULL) {296*seperator = 0;297sscanf(seperator+1,"%08X",&size);298}299300if (size != 1) {301AddFunction(value, address,size, 0);302} else {303AddLabel(value, address, 0);304}305}306}307308fclose(f);309return true;310}311312void SymbolMap::SaveNocashSym(const Path &filename) const {313std::lock_guard<std::recursive_mutex> guard(lock_);314315// Don't bother writing a blank file.316if (!File::Exists(filename) && functions.empty() && data.empty()) {317return;318}319320FILE* f = File::OpenCFile(filename, "w");321if (f == NULL)322return;323324// only write functions, the rest isn't really interesting325for (auto it = functions.begin(), end = functions.end(); it != end; ++it) {326const FunctionEntry& e = it->second;327fprintf(f, "%08X %s,%04X\n", GetModuleAbsoluteAddr(e.start,e.module),GetLabelNameRel(e.start, e.module), e.size);328}329330fclose(f);331}332333SymbolType SymbolMap::GetSymbolType(u32 address) {334if (activeNeedUpdate_)335UpdateActiveSymbols();336337std::lock_guard<std::recursive_mutex> guard(lock_);338if (activeFunctions.find(address) != activeFunctions.end())339return ST_FUNCTION;340if (activeData.find(address) != activeData.end())341return ST_DATA;342return ST_NONE;343}344345bool SymbolMap::GetSymbolInfo(SymbolInfo *info, u32 address, SymbolType symmask) {346u32 functionAddress = INVALID_ADDRESS;347u32 dataAddress = INVALID_ADDRESS;348349if (symmask & ST_FUNCTION) {350functionAddress = GetFunctionStart(address);351352// If both are found, we always return the function, so just do that early.353if (functionAddress != INVALID_ADDRESS) {354if (info != NULL) {355info->type = ST_FUNCTION;356info->address = functionAddress;357info->size = GetFunctionSize(functionAddress);358info->moduleAddress = GetFunctionModuleAddress(functionAddress);359}360361return true;362}363}364365if (symmask & ST_DATA) {366dataAddress = GetDataStart(address);367368if (dataAddress != INVALID_ADDRESS) {369if (info != NULL) {370info->type = ST_DATA;371info->address = dataAddress;372info->size = GetDataSize(dataAddress);373info->moduleAddress = GetDataModuleAddress(dataAddress);374}375376return true;377}378}379380return false;381}382383u32 SymbolMap::GetNextSymbolAddress(u32 address, SymbolType symmask) {384if (activeNeedUpdate_)385UpdateActiveSymbols();386387std::lock_guard<std::recursive_mutex> guard(lock_);388const auto functionEntry = symmask & ST_FUNCTION ? activeFunctions.upper_bound(address) : activeFunctions.end();389const auto dataEntry = symmask & ST_DATA ? activeData.upper_bound(address) : activeData.end();390391if (functionEntry == activeFunctions.end() && dataEntry == activeData.end())392return INVALID_ADDRESS;393394u32 funcAddress = (functionEntry != activeFunctions.end()) ? functionEntry->first : 0xFFFFFFFF;395u32 dataAddress = (dataEntry != activeData.end()) ? dataEntry->first : 0xFFFFFFFF;396397if (funcAddress <= dataAddress)398return funcAddress;399else400return dataAddress;401}402403std::string SymbolMap::GetDescription(unsigned int address) {404std::lock_guard<std::recursive_mutex> guard(lock_);405const char* labelName = NULL;406407u32 funcStart = GetFunctionStart(address);408if (funcStart != INVALID_ADDRESS) {409labelName = GetLabelName(funcStart);410} else {411u32 dataStart = GetDataStart(address);412if (dataStart != INVALID_ADDRESS)413labelName = GetLabelName(dataStart);414}415416if (labelName != NULL)417return labelName;418419char descriptionTemp[256];420sprintf(descriptionTemp, "(%08x)", address);421return descriptionTemp;422}423424std::vector<SymbolEntry> SymbolMap::GetAllSymbols(SymbolType symmask) {425if (activeNeedUpdate_)426UpdateActiveSymbols();427428std::vector<SymbolEntry> result;429430if (symmask & ST_FUNCTION) {431std::lock_guard<std::recursive_mutex> guard(lock_);432for (auto it = activeFunctions.begin(); it != activeFunctions.end(); it++) {433SymbolEntry entry;434entry.address = it->first;435entry.size = GetFunctionSize(entry.address);436const char* name = GetLabelName(entry.address);437if (name != NULL)438entry.name = name;439result.push_back(entry);440}441}442443if (symmask & ST_DATA) {444std::lock_guard<std::recursive_mutex> guard(lock_);445for (auto it = activeData.begin(); it != activeData.end(); it++) {446SymbolEntry entry;447entry.address = it->first;448entry.size = GetDataSize(entry.address);449const char* name = GetLabelName(entry.address);450if (name != NULL)451entry.name = name;452result.push_back(entry);453}454}455456return result;457}458459void SymbolMap::AddModule(const char *name, u32 address, u32 size) {460std::lock_guard<std::recursive_mutex> guard(lock_);461462for (auto it = modules.begin(), end = modules.end(); it != end; ++it) {463if (!strcmp(it->name, name)) {464// Just reactivate that one.465it->start = address;466it->size = size;467activeModuleEnds.emplace(it->start + it->size, *it);468activeNeedUpdate_ = true;469return;470}471}472473ModuleEntry mod;474truncate_cpy(mod.name, name);475mod.start = address;476mod.size = size;477mod.index = (int)modules.size() + 1;478479modules.push_back(mod);480activeModuleEnds.emplace(mod.start + mod.size, mod);481activeNeedUpdate_ = true;482}483484void SymbolMap::UnloadModule(u32 address, u32 size) {485std::lock_guard<std::recursive_mutex> guard(lock_);486activeModuleEnds.erase(address + size);487activeNeedUpdate_ = true;488}489490u32 SymbolMap::GetModuleRelativeAddr(u32 address, int moduleIndex) const {491std::lock_guard<std::recursive_mutex> guard(lock_);492if (moduleIndex == -1) {493moduleIndex = GetModuleIndex(address);494}495496for (auto it = modules.begin(), end = modules.end(); it != end; ++it) {497if (it->index == moduleIndex) {498return address - it->start;499}500}501return address;502}503504u32 SymbolMap::GetModuleAbsoluteAddr(u32 relative, int moduleIndex) const {505std::lock_guard<std::recursive_mutex> guard(lock_);506for (auto it = modules.begin(), end = modules.end(); it != end; ++it) {507if (it->index == moduleIndex) {508return it->start + relative;509}510}511return relative;512}513514int SymbolMap::GetModuleIndex(u32 address) const {515std::lock_guard<std::recursive_mutex> guard(lock_);516auto iter = activeModuleEnds.upper_bound(address);517if (iter == activeModuleEnds.end())518return -1;519return iter->second.index;520}521522bool SymbolMap::IsModuleActive(int moduleIndex) {523if (moduleIndex == 0) {524return true;525}526527std::lock_guard<std::recursive_mutex> guard(lock_);528for (auto it = activeModuleEnds.begin(), end = activeModuleEnds.end(); it != end; ++it) {529if (it->second.index == moduleIndex) {530return true;531}532}533return false;534}535536std::vector<LoadedModuleInfo> SymbolMap::getAllModules() const {537std::lock_guard<std::recursive_mutex> guard(lock_);538539std::vector<LoadedModuleInfo> result;540for (size_t i = 0; i < modules.size(); i++) {541LoadedModuleInfo m;542m.name = modules[i].name;543m.address = modules[i].start;544m.size = modules[i].size;545546u32 key = modules[i].start + modules[i].size;547m.active = activeModuleEnds.find(key) != activeModuleEnds.end();548549result.push_back(m);550}551552return result;553}554555void SymbolMap::AddFunction(const char* name, u32 address, u32 size, int moduleIndex) {556std::lock_guard<std::recursive_mutex> guard(lock_);557558if (moduleIndex == -1) {559moduleIndex = GetModuleIndex(address);560} else if (moduleIndex == 0) {561sawUnknownModule = true;562}563564// Is there an existing one?565u32 relAddress = GetModuleRelativeAddr(address, moduleIndex);566auto symbolKey = std::make_pair(moduleIndex, relAddress);567auto existing = functions.find(symbolKey);568if (sawUnknownModule && existing == functions.end()) {569// Fall back: maybe it's got moduleIndex = 0.570existing = functions.find(std::make_pair(0, address));571}572573if (existing != functions.end()) {574existing->second.size = size;575if (existing->second.module != moduleIndex) {576FunctionEntry func = existing->second;577func.start = relAddress;578func.module = moduleIndex;579functions.erase(existing);580functions[symbolKey] = func;581}582583// Refresh the active item if it exists.584auto active = activeFunctions.find(address);585if (active != activeFunctions.end() && active->second.module == moduleIndex) {586activeFunctions.erase(active);587activeFunctions.emplace(address, existing->second);588}589} else {590FunctionEntry func;591func.start = relAddress;592func.size = size;593func.index = (int)functions.size();594func.module = moduleIndex;595functions[symbolKey] = func;596597if (IsModuleActive(moduleIndex)) {598activeFunctions.emplace(address, func);599}600}601602AddLabel(name, address, moduleIndex);603}604605u32 SymbolMap::GetFunctionStart(u32 address) {606if (activeNeedUpdate_)607UpdateActiveSymbols();608609std::lock_guard<std::recursive_mutex> guard(lock_);610auto it = activeFunctions.upper_bound(address);611if (it == activeFunctions.end()) {612// check last element613auto rit = activeFunctions.rbegin();614if (rit != activeFunctions.rend()) {615u32 start = rit->first;616u32 size = rit->second.size;617if (start <= address && start+size > address)618return start;619}620// otherwise there's no function that contains this address621return INVALID_ADDRESS;622}623624if (it != activeFunctions.begin()) {625it--;626u32 start = it->first;627u32 size = it->second.size;628if (start <= address && start+size > address)629return start;630}631632return INVALID_ADDRESS;633}634635u32 SymbolMap::FindPossibleFunctionAtAfter(u32 address) {636if (activeNeedUpdate_)637UpdateActiveSymbols();638639std::lock_guard<std::recursive_mutex> guard(lock_);640auto it = activeFunctions.lower_bound(address);641if (it == activeFunctions.end()) {642return (u32)-1;643}644return it->first;645}646647u32 SymbolMap::GetFunctionSize(u32 startAddress) {648if (activeNeedUpdate_) {649std::lock_guard<std::recursive_mutex> guard(lock_);650651// This is common, from the jit. Direct lookup is faster than updating active symbols.652auto mod = activeModuleEnds.lower_bound(startAddress);653std::pair<int, u32> funcKey;654if (mod == activeModuleEnds.end()) {655// Could still be mod 0, backwards compatibility.656if (!sawUnknownModule)657return INVALID_ADDRESS;658funcKey.first = 0;659funcKey.second = startAddress;660} else {661if (mod->second.start > startAddress)662return INVALID_ADDRESS;663funcKey.first = mod->second.index;664funcKey.second = startAddress - mod->second.start;665}666667auto func = functions.find(funcKey);668if (func == functions.end())669return INVALID_ADDRESS;670671return func->second.size;672}673674std::lock_guard<std::recursive_mutex> guard(lock_);675auto it = activeFunctions.find(startAddress);676if (it == activeFunctions.end())677return INVALID_ADDRESS;678679return it->second.size;680}681682u32 SymbolMap::GetFunctionModuleAddress(u32 startAddress) {683if (activeNeedUpdate_)684UpdateActiveSymbols();685686std::lock_guard<std::recursive_mutex> guard(lock_);687auto it = activeFunctions.find(startAddress);688if (it == activeFunctions.end())689return INVALID_ADDRESS;690691return GetModuleAbsoluteAddr(0, it->second.module);692}693694int SymbolMap::GetFunctionNum(u32 address) {695if (activeNeedUpdate_)696UpdateActiveSymbols();697698std::lock_guard<std::recursive_mutex> guard(lock_);699u32 start = GetFunctionStart(address);700if (start == INVALID_ADDRESS)701return INVALID_ADDRESS;702703auto it = activeFunctions.find(start);704if (it == activeFunctions.end())705return INVALID_ADDRESS;706707return it->second.index;708}709710void SymbolMap::AssignFunctionIndices() {711std::lock_guard<std::recursive_mutex> guard(lock_);712int index = 0;713for (auto mod = activeModuleEnds.begin(), modend = activeModuleEnds.end(); mod != modend; ++mod) {714int moduleIndex = mod->second.index;715auto begin = functions.lower_bound(std::make_pair(moduleIndex, 0));716auto end = functions.upper_bound(std::make_pair(moduleIndex, 0xFFFFFFFF));717for (auto it = begin; it != end; ++it) {718it->second.index = index++;719}720}721}722723void SymbolMap::UpdateActiveSymbols() {724// return; (slow in debug mode)725std::lock_guard<std::recursive_mutex> guard(lock_);726727activeFunctions.clear();728activeLabels.clear();729activeData.clear();730731// On startup and shutdown, we can skip the rest. Tiny optimization.732if (activeModuleEnds.empty() || (functions.empty() && labels.empty() && data.empty())) {733return;734}735736std::unordered_map<int, u32> activeModuleIndexes;737for (auto it = activeModuleEnds.begin(), end = activeModuleEnds.end(); it != end; ++it) {738activeModuleIndexes[it->second.index] = it->second.start;739}740741for (auto it = functions.begin(), end = functions.end(); it != end; ++it) {742const auto mod = activeModuleIndexes.find(it->second.module);743if (it->second.module == 0) {744activeFunctions.emplace(it->second.start, it->second);745} else if (mod != activeModuleIndexes.end()) {746activeFunctions.emplace(mod->second + it->second.start, it->second);747}748}749750for (auto it = labels.begin(), end = labels.end(); it != end; ++it) {751const auto mod = activeModuleIndexes.find(it->second.module);752if (it->second.module == 0) {753activeLabels.emplace(it->second.addr, it->second);754} else if (mod != activeModuleIndexes.end()) {755activeLabels.emplace(mod->second + it->second.addr, it->second);756}757}758759for (auto it = data.begin(), end = data.end(); it != end; ++it) {760const auto mod = activeModuleIndexes.find(it->second.module);761if (it->second.module == 0) {762activeData.emplace(it->second.start, it->second);763} else if (mod != activeModuleIndexes.end()) {764activeData.emplace(mod->second + it->second.start, it->second);765}766}767768AssignFunctionIndices();769activeNeedUpdate_ = false;770}771772bool SymbolMap::SetFunctionSize(u32 startAddress, u32 newSize) {773if (activeNeedUpdate_)774UpdateActiveSymbols();775776std::lock_guard<std::recursive_mutex> guard(lock_);777778auto funcInfo = activeFunctions.find(startAddress);779if (funcInfo != activeFunctions.end()) {780auto symbolKey = std::make_pair(funcInfo->second.module, funcInfo->second.start);781auto func = functions.find(symbolKey);782if (func != functions.end()) {783func->second.size = newSize;784activeFunctions.erase(funcInfo);785activeFunctions.emplace(startAddress, func->second);786}787}788789// TODO: check for overlaps790return true;791}792793bool SymbolMap::RemoveFunction(u32 startAddress, bool removeName) {794if (activeNeedUpdate_)795UpdateActiveSymbols();796797std::lock_guard<std::recursive_mutex> guard(lock_);798799auto it = activeFunctions.find(startAddress);800if (it == activeFunctions.end())801return false;802803auto symbolKey = std::make_pair(it->second.module, it->second.start);804auto it2 = functions.find(symbolKey);805if (it2 != functions.end()) {806functions.erase(it2);807}808activeFunctions.erase(it);809810if (removeName) {811auto labelIt = activeLabels.find(startAddress);812if (labelIt != activeLabels.end()) {813symbolKey = std::make_pair(labelIt->second.module, labelIt->second.addr);814auto labelIt2 = labels.find(symbolKey);815if (labelIt2 != labels.end()) {816labels.erase(labelIt2);817}818activeLabels.erase(labelIt);819}820}821822return true;823}824825void SymbolMap::AddLabel(const char* name, u32 address, int moduleIndex) {826std::lock_guard<std::recursive_mutex> guard(lock_);827828if (moduleIndex == -1) {829moduleIndex = GetModuleIndex(address);830} else if (moduleIndex == 0) {831sawUnknownModule = true;832}833834// Is there an existing one?835u32 relAddress = GetModuleRelativeAddr(address, moduleIndex);836auto symbolKey = std::make_pair(moduleIndex, relAddress);837auto existing = labels.find(symbolKey);838if (sawUnknownModule && existing == labels.end()) {839// Fall back: maybe it's got moduleIndex = 0.840existing = labels.find(std::make_pair(0, address));841}842843if (existing != labels.end()) {844// We leave an existing label alone, rather than overwriting.845// But we'll still upgrade it to the correct module / relative address.846if (existing->second.module != moduleIndex) {847LabelEntry label = existing->second;848label.addr = relAddress;849label.module = moduleIndex;850labels.erase(existing);851labels[symbolKey] = label;852853// Refresh the active item if it exists.854auto active = activeLabels.find(address);855if (active != activeLabels.end() && active->second.module == moduleIndex) {856activeLabels.erase(active);857activeLabels.emplace(address, label);858}859}860} else {861LabelEntry label;862label.addr = relAddress;863label.module = moduleIndex;864truncate_cpy(label.name, name);865866labels[symbolKey] = label;867if (IsModuleActive(moduleIndex)) {868activeLabels.emplace(address, label);869}870}871}872873void SymbolMap::SetLabelName(const char* name, u32 address) {874if (activeNeedUpdate_)875UpdateActiveSymbols();876877std::lock_guard<std::recursive_mutex> guard(lock_);878auto labelInfo = activeLabels.find(address);879if (labelInfo == activeLabels.end()) {880AddLabel(name, address);881} else {882auto symbolKey = std::make_pair(labelInfo->second.module, labelInfo->second.addr);883auto label = labels.find(symbolKey);884if (label != labels.end()) {885truncate_cpy(label->second.name, name);886label->second.name[127] = 0;887888// Refresh the active item if it exists.889auto active = activeLabels.find(address);890if (active != activeLabels.end() && active->second.module == label->second.module) {891activeLabels.erase(active);892activeLabels.emplace(address, label->second);893}894}895}896}897898const char *SymbolMap::GetLabelName(u32 address) {899if (activeNeedUpdate_)900UpdateActiveSymbols();901902std::lock_guard<std::recursive_mutex> guard(lock_);903auto it = activeLabels.find(address);904if (it == activeLabels.end())905return NULL;906907return it->second.name;908}909910const char *SymbolMap::GetLabelNameRel(u32 relAddress, int moduleIndex) const {911std::lock_guard<std::recursive_mutex> guard(lock_);912auto it = labels.find(std::make_pair(moduleIndex, relAddress));913if (it == labels.end())914return NULL;915916return it->second.name;917}918919std::string SymbolMap::GetLabelString(u32 address) {920std::lock_guard<std::recursive_mutex> guard(lock_);921const char *label = GetLabelName(address);922if (label == NULL)923return "";924return label;925}926927bool SymbolMap::GetLabelValue(const char* name, u32& dest) {928if (activeNeedUpdate_)929UpdateActiveSymbols();930931std::lock_guard<std::recursive_mutex> guard(lock_);932for (auto it = activeLabels.begin(); it != activeLabels.end(); it++) {933if (strcasecmp(name, it->second.name) == 0) {934dest = it->first;935return true;936}937}938939return false;940}941942void SymbolMap::AddData(u32 address, u32 size, DataType type, int moduleIndex) {943std::lock_guard<std::recursive_mutex> guard(lock_);944945if (moduleIndex == -1) {946moduleIndex = GetModuleIndex(address);947} else if (moduleIndex == 0) {948sawUnknownModule = true;949}950951// Is there an existing one?952u32 relAddress = GetModuleRelativeAddr(address, moduleIndex);953auto symbolKey = std::make_pair(moduleIndex, relAddress);954auto existing = data.find(symbolKey);955if (sawUnknownModule && existing == data.end()) {956// Fall back: maybe it's got moduleIndex = 0.957existing = data.find(std::make_pair(0, address));958}959960if (existing != data.end()) {961existing->second.size = size;962existing->second.type = type;963if (existing->second.module != moduleIndex) {964DataEntry entry = existing->second;965entry.module = moduleIndex;966entry.start = relAddress;967data.erase(existing);968data[symbolKey] = entry;969}970971// Refresh the active item if it exists.972auto active = activeData.find(address);973if (active != activeData.end() && active->second.module == moduleIndex) {974activeData.erase(active);975activeData.emplace(address, existing->second);976}977} else {978DataEntry entry;979entry.start = relAddress;980entry.size = size;981entry.type = type;982entry.module = moduleIndex;983984data[symbolKey] = entry;985if (IsModuleActive(moduleIndex)) {986activeData.emplace(address, entry);987}988}989}990991u32 SymbolMap::GetDataStart(u32 address) {992if (activeNeedUpdate_)993UpdateActiveSymbols();994995std::lock_guard<std::recursive_mutex> guard(lock_);996auto it = activeData.upper_bound(address);997if (it == activeData.end())998{999// check last element1000auto rit = activeData.rbegin();10011002if (rit != activeData.rend())1003{1004u32 start = rit->first;1005u32 size = rit->second.size;1006if (start <= address && start+size > address)1007return start;1008}1009// otherwise there's no data that contains this address1010return INVALID_ADDRESS;1011}10121013if (it != activeData.begin()) {1014it--;1015u32 start = it->first;1016u32 size = it->second.size;1017if (start <= address && start+size > address)1018return start;1019}10201021return INVALID_ADDRESS;1022}10231024u32 SymbolMap::GetDataSize(u32 startAddress) {1025if (activeNeedUpdate_)1026UpdateActiveSymbols();10271028std::lock_guard<std::recursive_mutex> guard(lock_);1029auto it = activeData.find(startAddress);1030if (it == activeData.end())1031return INVALID_ADDRESS;1032return it->second.size;1033}10341035u32 SymbolMap::GetDataModuleAddress(u32 startAddress) {1036if (activeNeedUpdate_)1037UpdateActiveSymbols();10381039std::lock_guard<std::recursive_mutex> guard(lock_);1040auto it = activeData.find(startAddress);1041if (it == activeData.end())1042return INVALID_ADDRESS;1043return GetModuleAbsoluteAddr(0, it->second.module);1044}10451046DataType SymbolMap::GetDataType(u32 startAddress) {1047if (activeNeedUpdate_)1048UpdateActiveSymbols();10491050std::lock_guard<std::recursive_mutex> guard(lock_);1051auto it = activeData.find(startAddress);1052if (it == activeData.end())1053return DATATYPE_NONE;1054return it->second.type;1055}10561057void SymbolMap::GetLabels(std::vector<LabelDefinition> &dest) {1058if (activeNeedUpdate_)1059UpdateActiveSymbols();10601061std::lock_guard<std::recursive_mutex> guard(lock_);1062for (auto it = activeLabels.begin(); it != activeLabels.end(); it++) {1063LabelDefinition entry;1064entry.value = it->first;1065std::string name = it->second.name;1066std::transform(name.begin(), name.end(), name.begin(), ::tolower);1067entry.name = Identifier(name);1068dest.push_back(entry);1069}1070}10711072#if defined(_WIN32) && !PPSSPP_PLATFORM(UWP)10731074struct DefaultSymbol {1075u32 address;1076const char* name;1077};10781079static const DefaultSymbol defaultSymbols[]= {1080{ 0x08800000, "User memory" },1081{ 0x08804000, "Default load address" },1082{ 0x04000000, "VRAM" },1083{ 0x88000000, "Kernel memory" },1084{ 0x00010000, "Scratchpad" },1085};10861087void SymbolMap::FillSymbolListBox(HWND listbox,SymbolType symType) {1088if (activeNeedUpdate_)1089UpdateActiveSymbols();10901091wchar_t temp[256];1092std::lock_guard<std::recursive_mutex> guard(lock_);10931094SendMessage(listbox, WM_SETREDRAW, FALSE, 0);1095ListBox_ResetContent(listbox);10961097switch (symType) {1098case ST_FUNCTION:1099{1100SendMessage(listbox, LB_INITSTORAGE, (WPARAM)activeFunctions.size(), (LPARAM)activeFunctions.size() * 30);11011102for (auto it = activeFunctions.begin(), end = activeFunctions.end(); it != end; ++it) {1103const char* name = GetLabelName(it->first);1104if (name != NULL)1105wsprintf(temp, L"%S", name);1106else1107wsprintf(temp, L"0x%08X", it->first);1108int index = ListBox_AddString(listbox,temp);1109ListBox_SetItemData(listbox,index,it->first);1110}1111}1112break;11131114case ST_DATA:1115{1116size_t count = ARRAYSIZE(defaultSymbols)+activeData.size();1117SendMessage(listbox, LB_INITSTORAGE, (WPARAM)count, (LPARAM)count * 30);11181119for (int i = 0; i < ARRAYSIZE(defaultSymbols); i++) {1120wsprintf(temp, L"0x%08X (%S)", defaultSymbols[i].address, defaultSymbols[i].name);1121int index = ListBox_AddString(listbox,temp);1122ListBox_SetItemData(listbox,index,defaultSymbols[i].address);1123}11241125for (auto it = activeData.begin(), end = activeData.end(); it != end; ++it) {1126const char* name = GetLabelName(it->first);11271128if (name != NULL)1129wsprintf(temp, L"%S", name);1130else1131wsprintf(temp, L"0x%08X", it->first);11321133int index = ListBox_AddString(listbox,temp);1134ListBox_SetItemData(listbox,index,it->first);1135}1136}1137break;1138}11391140SendMessage(listbox, WM_SETREDRAW, TRUE, 0);1141RedrawWindow(listbox, NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);1142}1143#endif114411451146