ppsspp/Core/Debugger/SymbolMap.cpp

667 lines
14 KiB
C++
Raw Normal View History

2012-11-01 16:19:01 +01:00
// Copyright (c) 2012- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
2012-11-01 16:19:01 +01:00
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#ifdef _WIN32
#include "Common/CommonWindows.h"
2012-11-01 16:19:01 +01:00
#include <WindowsX.h>
#else
#include <unistd.h>
#endif
#include <algorithm>
#include "Common/FileUtil.h"
#include "Globals.h"
#include "Core/MemMap.h"
#include "Core/Debugger/SymbolMap.h"
2012-11-01 16:19:01 +01:00
SymbolMap symbolMap;
void SymbolMap::SortSymbols()
{
lock_guard guard(lock_);
2013-11-27 13:33:30 +01:00
AssignFunctionIndices();
2012-11-01 16:19:01 +01:00
}
void SymbolMap::Clear() {
lock_guard guard(lock_);
2013-11-27 13:33:30 +01:00
functions.clear();
labels.clear();
data.clear();
}
2012-11-01 16:19:01 +01:00
bool SymbolMap::LoadSymbolMap(const char *filename)
{
lock_guard guard(lock_);
Clear();
FILE *f = File::OpenCFile(filename, "r");
2012-11-01 16:19:01 +01:00
if (!f)
return false;
//char temp[256];
//fgets(temp,255,f); //.text section layout
//fgets(temp,255,f); // Starting Virtual
//fgets(temp,255,f); // address Size address
//fgets(temp,255,f); // -----------------------
bool started=false;
while (!feof(f))
{
2013-08-12 23:33:11 -07:00
char line[512], temp[256] = {0};
char *p = fgets(line,512,f);
if(p == NULL)
break;
// Chop any newlines off.
for (size_t i = strlen(line) - 1; i > 0; i--) {
if (line[i] == '\r' || line[i] == '\n') {
line[i] = '\0';
}
}
if (strlen(line) < 4 || sscanf(line, "%s", temp) != 1)
2012-11-01 16:19:01 +01:00
continue;
if (strcmp(temp,"UNUSED")==0) continue;
if (strcmp(temp,".text")==0) {started=true;continue;};
if (strcmp(temp,".init")==0) {started=true;continue;};
if (strcmp(temp,"Starting")==0) continue;
if (strcmp(temp,"extab")==0) continue;
if (strcmp(temp,".ctors")==0) break;
if (strcmp(temp,".dtors")==0) break;
if (strcmp(temp,".rodata")==0) continue;
if (strcmp(temp,".data")==0) continue;
if (strcmp(temp,".sbss")==0) continue;
if (strcmp(temp,".sdata")==0) continue;
if (strcmp(temp,".sdata2")==0) continue;
if (strcmp(temp,"address")==0) continue;
if (strcmp(temp,"-----------------------")==0) continue;
if (strcmp(temp,".sbss2")==0) break;
if (temp[1]==']') continue;
if (!started) continue;
2013-11-27 13:33:30 +01:00
u32 address,size,vaddress;
SymbolType type;
char name[128] = {0};
2013-11-27 13:33:30 +01:00
sscanf(line,"%08x %08x %08x %i %127c",&address,&size,&vaddress,(int*)&type,name);
2012-11-01 16:19:01 +01:00
2013-11-27 13:33:30 +01:00
if (type == ST_DATA && size==0)
size=4;
2012-11-01 16:19:01 +01:00
//e.vaddress|=0x80000000;
2013-11-27 13:33:30 +01:00
if (strcmp(name,".text")==0 || strcmp(name,".init")==0 || strlen(name)<=1) {
;
} else {
2013-11-27 13:33:30 +01:00
switch (type)
{
case ST_FUNCTION:
AddFunction(name,vaddress,size);
break;
case ST_DATA:
AddData(vaddress,size,DATATYPE_BYTE);
if (name[0] != 0)
AddLabel(name,vaddress);
break;
}
}
2012-11-01 16:19:01 +01:00
}
fclose(f);
SortSymbols();
2012-11-01 16:19:01 +01:00
return true;
}
void SymbolMap::SaveSymbolMap(const char *filename) const
2012-11-01 16:19:01 +01:00
{
lock_guard guard(lock_);
FILE *f = File::OpenCFile(filename, "w");
2012-11-01 16:19:01 +01:00
if (!f)
return;
fprintf(f,".text\n");
2013-11-27 13:33:30 +01:00
for (auto it = functions.begin(), end = functions.end(); it != end; ++it)
2012-11-01 16:19:01 +01:00
{
2013-11-27 13:33:30 +01:00
const FunctionEntry& e = it->second;
fprintf(f,"%08x %08x %08x %i %s\n",it->first,e.size,it->first,ST_FUNCTION,GetLabelName(it->first));
}
for (auto it = data.begin(), end = data.end(); it != end; ++it)
{
const DataEntry& e = it->second;
fprintf(f,"%08x %08x %08x %i %s\n",it->first,e.size,it->first,ST_DATA,GetLabelName(it->first));
2012-11-01 16:19:01 +01:00
}
fclose(f);
}
2013-07-29 13:06:01 +02:00
bool SymbolMap::LoadNocashSym(const char *filename)
{
lock_guard guard(lock_);
FILE *f = File::OpenCFile(filename, "r");
2013-07-29 13:06:01 +02:00
if (!f)
return false;
while (!feof(f))
{
2013-08-12 23:33:11 -07:00
char line[256], value[256] = {0};
2013-07-29 13:06:01 +02:00
char *p = fgets(line,256,f);
if(p == NULL)
break;
u32 address;
if (sscanf(line,"%08X %s",&address,value) != 2) continue;
if (address == 0 && strcmp(value,"0") == 0) continue;
if (value[0] == '.') // data directives
{
2013-11-27 13:33:30 +01:00
char* s = strchr(value,':');
if (s != NULL)
{
*s = 0;
u32 size = 0;
if (sscanf(s+1,"%04X",&size) != 1) continue;
if (strcasecmp(value,".byt") == 0)
{
AddData(address,size,DATATYPE_BYTE);
} else if (strcasecmp(value,".wrd") == 0)
{
AddData(address,size,DATATYPE_HALFWORD);
} else if (strcasecmp(value,".dbl") == 0)
{
AddData(address,size,DATATYPE_WORD);
2013-11-28 00:33:21 +01:00
} else if (strcasecmp(value,".asc") == 0)
{
AddData(address,size,DATATYPE_ASCII);
2013-11-27 13:33:30 +01:00
}
}
2013-07-29 13:06:01 +02:00
} else { // labels
2013-11-01 14:14:06 +01:00
int size = 1;
char* seperator = strchr(value,',');
if (seperator != NULL)
{
*seperator = 0;
sscanf(seperator+1,"%08X",&size);
}
2013-11-26 00:23:17 +01:00
if (size != 1)
{
2013-11-27 13:33:30 +01:00
AddFunction(value,address,size);
2013-11-26 00:23:17 +01:00
} else {
AddLabel(value,address);
}
2013-07-29 13:06:01 +02:00
}
}
fclose(f);
return true;
}
2013-11-27 13:33:30 +01:00
SymbolType SymbolMap::GetSymbolType(u32 address) const
2012-11-01 16:19:01 +01:00
{
2013-11-27 13:33:30 +01:00
if (functions.find(address) != functions.end())
return ST_FUNCTION;
if (data.find(address) != data.end())
return ST_DATA;
return ST_NONE;
2012-11-01 16:19:01 +01:00
}
bool SymbolMap::GetSymbolInfo(SymbolInfo *info, u32 address, SymbolType symmask) const
{
2013-11-27 13:33:30 +01:00
u32 functionAddress = -1;
u32 dataAddress = -1;
if (symmask & ST_FUNCTION)
functionAddress = GetFunctionStart(address);
2013-11-27 13:33:30 +01:00
if (symmask & ST_DATA)
dataAddress = GetDataStart(address);
if (functionAddress == -1 || dataAddress == -1)
{
2013-11-27 13:33:30 +01:00
if (functionAddress != -1)
{
2013-11-27 13:33:30 +01:00
if (info != NULL)
{
info->type = ST_FUNCTION;
info->address = functionAddress;
info->size = GetFunctionSize(functionAddress);
}
return true;
}
2013-11-27 13:33:30 +01:00
if (dataAddress != -1)
{
if (info != NULL)
{
info->type = ST_DATA;
info->address = dataAddress;
2013-11-28 00:33:21 +01:00
info->size = GetDataSize(dataAddress);
2013-11-27 13:33:30 +01:00
}
return true;
}
return false;
}
2013-11-27 13:33:30 +01:00
// if both exist, return the function
if (info != NULL)
{
2013-11-27 13:33:30 +01:00
info->type = ST_FUNCTION;
info->address = functionAddress;
info->size = GetFunctionSize(functionAddress);
}
2013-11-27 13:33:30 +01:00
return true;
}
2013-11-27 13:33:30 +01:00
u32 SymbolMap::GetNextSymbolAddress(u32 address, SymbolType symmask)
{
2013-11-27 13:33:30 +01:00
const auto functionEntry = symmask & ST_FUNCTION ? functions.upper_bound(address) : functions.end();
const auto dataEntry = symmask & ST_DATA ? data.upper_bound(address) : data.end();
if (functionEntry == functions.end() && dataEntry == data.end())
return -1;
2013-11-27 13:33:30 +01:00
u32 funcAddress = (functionEntry != functions.end()) ? functionEntry->first : 0xFFFFFFFF;
u32 dataAddress = (dataEntry != data.end()) ? dataEntry->first : 0xFFFFFFFF;
if (funcAddress <= dataAddress)
return funcAddress;
else
return dataAddress;
}
2013-11-26 00:23:17 +01:00
2013-11-27 13:33:30 +01:00
static char descriptionTemp[256];
2013-11-26 00:23:17 +01:00
2013-11-27 13:33:30 +01:00
const char *SymbolMap::GetDescription(unsigned int address) const
2013-11-26 00:23:17 +01:00
{
2013-11-27 13:33:30 +01:00
const char* labelName = NULL;
2013-11-26 00:23:17 +01:00
2013-11-27 13:33:30 +01:00
u32 funcStart = GetFunctionStart(address);
if (funcStart != -1)
{
2013-11-27 13:33:30 +01:00
labelName = GetLabelName(funcStart);
} else {
u32 dataStart = GetDataStart(address);
if (dataStart != -1)
labelName = GetLabelName(dataStart);
}
2013-11-27 13:33:30 +01:00
if (labelName != NULL)
return labelName;
2013-11-27 13:33:30 +01:00
sprintf(descriptionTemp, "(%08x)", address);
return descriptionTemp;
}
2013-11-27 15:06:41 +01:00
std::vector<SymbolEntry> SymbolMap::GetAllSymbols(SymbolType symmask)
{
std::vector<SymbolEntry> result;
if (symmask & ST_FUNCTION)
{
for (auto it = functions.begin(); it != functions.end(); it++)
{
SymbolEntry entry;
entry.address = it->first;
entry.size = GetFunctionSize(entry.address);
const char* name = GetLabelName(entry.address);
if (name != NULL)
entry.name = name;
result.push_back(entry);
}
}
if (symmask & ST_DATA)
{
for (auto it = data.begin(); it != data.end(); it++)
{
SymbolEntry entry;
entry.address = it->first;
entry.size = GetDataSize(entry.address);
const char* name = GetLabelName(entry.address);
if (name != NULL)
entry.name = name;
result.push_back(entry);
}
}
2012-11-01 16:19:01 +01:00
2013-11-27 15:06:41 +01:00
return result;
}
2012-11-01 16:19:01 +01:00
2013-11-27 13:33:30 +01:00
void SymbolMap::AddFunction(const char* name, u32 address, u32 size)
{
lock_guard guard(lock_);
2013-11-27 13:33:30 +01:00
FunctionEntry func;
func.size = size;
func.index = (int)functions.size();
functions[address] = func;
2013-11-27 13:33:30 +01:00
if (GetLabelName(address) == NULL)
AddLabel(name,address);
}
2013-11-27 13:33:30 +01:00
u32 SymbolMap::GetFunctionStart(u32 address) const
2012-11-01 16:19:01 +01:00
{
2013-11-27 13:33:30 +01:00
auto it = functions.upper_bound(address);
if (it == functions.end())
{
2013-11-27 13:33:30 +01:00
// check last element
auto rit = functions.rbegin();
if (rit != functions.rend())
{
2013-11-27 13:33:30 +01:00
u32 start = rit->first;
u32 size = rit->second.size;
if (start <= address && start+size > address)
return start;
}
2013-11-27 13:33:30 +01:00
// otherwise there's no function that contains this address
return -1;
}
2012-11-01 16:19:01 +01:00
2013-11-27 13:33:30 +01:00
if (it != functions.begin())
2012-11-01 16:19:01 +01:00
{
2013-11-27 13:33:30 +01:00
it--;
u32 start = it->first;
u32 size = it->second.size;
if (start <= address && start+size > address)
return start;
2012-11-01 16:19:01 +01:00
}
2013-11-27 13:33:30 +01:00
return -1;
2012-11-01 16:19:01 +01:00
}
2013-11-27 13:33:30 +01:00
u32 SymbolMap::GetFunctionSize(u32 startAddress) const
2012-11-01 16:19:01 +01:00
{
2013-11-27 13:33:30 +01:00
auto it = functions.find(startAddress);
if (it == functions.end())
return -1;
2012-11-01 16:19:01 +01:00
2013-11-27 13:33:30 +01:00
return it->second.size;
}
2012-11-01 16:19:01 +01:00
2013-11-27 13:33:30 +01:00
int SymbolMap::GetFunctionNum(u32 address) const
{
u32 start = GetFunctionStart(address);
if (start == -1)
return -1;
2012-11-01 16:19:01 +01:00
2013-11-27 13:33:30 +01:00
auto it = functions.find(start);
if (it == functions.end())
return -1;
2012-11-01 16:19:01 +01:00
2013-11-27 13:33:30 +01:00
return it->second.index;
}
2013-11-27 13:33:30 +01:00
void SymbolMap::AssignFunctionIndices()
{
int index = 0;
for (auto it = functions.begin(); it != functions.end(); it++)
2012-11-01 16:19:01 +01:00
{
2013-11-27 13:33:30 +01:00
it->second.index = index++;
2012-11-01 16:19:01 +01:00
}
}
2013-11-27 13:33:30 +01:00
bool SymbolMap::SetFunctionSize(u32 startAddress, u32 newSize)
{
lock_guard guard(lock_);
2013-11-27 13:33:30 +01:00
auto it = functions.find(startAddress);
if (it == functions.end())
return false;
2012-11-01 16:19:01 +01:00
2013-11-27 13:33:30 +01:00
it->second.size = newSize;
// TODO: check for overlaps
return true;
2012-11-01 16:19:01 +01:00
}
2013-11-27 13:33:30 +01:00
bool SymbolMap::RemoveFunction(u32 startAddress, bool removeName)
2012-11-01 16:19:01 +01:00
{
lock_guard guard(lock_);
2013-11-27 13:33:30 +01:00
auto it = functions.find(startAddress);
if (it == functions.end())
return false;
functions.erase(it);
if (removeName)
{
auto labelIt = labels.find(startAddress);
if (labelIt != labels.end())
labels.erase(labelIt);
}
return true;
2012-11-01 16:19:01 +01:00
}
2013-11-27 13:33:30 +01:00
void SymbolMap::AddLabel(const char* name, u32 address)
{
2013-11-27 13:33:30 +01:00
// keep a label if it already exists
auto it = labels.find(address);
if (it == labels.end())
{
LabelEntry label;
strcpy(label.name,name);
label.name[127] = 0;
labels[address] = label;
}
}
2013-11-27 13:33:30 +01:00
void SymbolMap::SetLabelName(const char* name, u32 address)
2012-11-01 16:19:01 +01:00
{
2013-11-27 13:33:30 +01:00
auto it = labels.find(address);
if (it == labels.end())
{
LabelEntry label;
strcpy(label.name,name);
label.name[127] = 0;
labels[address] = label;
} else {
strcpy(it->second.name,name);
it->second.name[127] = 0;
}
2012-11-01 16:19:01 +01:00
}
2013-11-27 13:33:30 +01:00
const char* SymbolMap::GetLabelName(u32 address) const
2012-11-01 16:19:01 +01:00
{
2013-11-27 13:33:30 +01:00
auto it = labels.find(address);
if (it == labels.end())
return NULL;
return it->second.name;
2012-11-01 16:19:01 +01:00
}
2013-11-27 13:33:30 +01:00
bool SymbolMap::GetLabelValue(const char* name, u32& dest)
{
for (auto it = labels.begin(); it != labels.end(); it++)
{
if (strcasecmp(name,it->second.name) == 0)
{
dest = it->first;
return true;
}
}
2013-11-27 13:33:30 +01:00
return false;
}
2012-11-01 16:19:01 +01:00
2013-11-27 13:33:30 +01:00
void SymbolMap::AddData(u32 address, u32 size, DataType type)
2012-11-01 16:19:01 +01:00
{
2013-11-27 13:33:30 +01:00
DataEntry entry;
entry.size = size;
entry.type = type;
data[address] = entry;
2012-11-01 16:19:01 +01:00
}
2013-11-27 13:33:30 +01:00
u32 SymbolMap::GetDataStart(u32 address) const
2012-11-01 16:19:01 +01:00
{
2013-11-27 13:33:30 +01:00
auto it = data.upper_bound(address);
if (it == data.end())
{
// check last element
auto rit = data.rbegin();
if (rit != data.rend())
{
u32 start = rit->first;
u32 size = rit->second.size;
if (start <= address && start+size > address)
return start;
}
// otherwise there's no data that contains this address
return -1;
}
if (it != data.begin())
{
it--;
u32 start = it->first;
u32 size = it->second.size;
if (start <= address && start+size > address)
return start;
}
2012-11-01 16:19:01 +01:00
return -1;
}
2013-11-27 13:33:30 +01:00
u32 SymbolMap::GetDataSize(u32 startAddress) const
2012-11-01 16:19:01 +01:00
{
2013-11-27 13:33:30 +01:00
auto it = data.find(startAddress);
if (it == data.end())
return -1;
return it->second.size;
2012-11-01 16:19:01 +01:00
}
2013-11-27 13:33:30 +01:00
DataType SymbolMap::GetDataType(u32 startAddress) const
2012-11-01 16:19:01 +01:00
{
2013-11-27 13:33:30 +01:00
auto it = data.find(startAddress);
if (it == data.end())
return DATATYPE_NONE;
return it->second.type;
2012-11-01 16:19:01 +01:00
}
2013-11-27 13:33:30 +01:00
#ifdef _WIN32
struct DefaultSymbol
2012-11-01 16:19:01 +01:00
{
2013-11-27 13:33:30 +01:00
u32 address;
const char* name;
};
2012-11-01 16:19:01 +01:00
2013-11-27 13:33:30 +01:00
static const DefaultSymbol defaultSymbols[]= {
{ 0x08800000, "User memory" },
{ 0x08804000, "Default load address" },
{ 0x04000000, "VRAM" },
{ 0x88000000, "Kernel memory" },
{ 0x00010000, "Scratchpad" },
};
2012-11-01 16:19:01 +01:00
2013-11-27 13:33:30 +01:00
void SymbolMap::FillSymbolListBox(HWND listbox,SymbolType symType) const
2012-11-01 16:19:01 +01:00
{
2013-11-27 13:33:30 +01:00
wchar_t temp[256];
lock_guard guard(lock_);
SendMessage(listbox, WM_SETREDRAW, FALSE, 0);
ListBox_ResetContent(listbox);
switch (symType)
2012-11-01 16:19:01 +01:00
{
2013-11-27 13:33:30 +01:00
case ST_FUNCTION:
2012-11-01 16:19:01 +01:00
{
2013-11-27 13:33:30 +01:00
SendMessage(listbox, LB_INITSTORAGE, (WPARAM)functions.size(), (LPARAM)functions.size() * 30);
for (auto it = functions.begin(), end = functions.end(); it != end; ++it)
2012-11-01 16:19:01 +01:00
{
2013-11-27 13:33:30 +01:00
const FunctionEntry& entry = it->second;
const char* name = GetLabelName(it->first);
if (name != NULL)
wsprintf(temp, L"%S", name);
else
wsprintf(temp, L"0x%08X", it->first);
int index = ListBox_AddString(listbox,temp);
ListBox_SetItemData(listbox,index,it->first);
2012-11-01 16:19:01 +01:00
}
}
2013-11-27 13:33:30 +01:00
break;
2012-11-01 16:19:01 +01:00
2013-11-27 13:33:30 +01:00
case ST_DATA:
{
int count = ARRAYSIZE(defaultSymbols)+(int)data.size();
SendMessage(listbox, LB_INITSTORAGE, (WPARAM)count, (LPARAM)count * 30);
2012-11-01 16:19:01 +01:00
2013-11-27 13:33:30 +01:00
for (int i = 0; i < ARRAYSIZE(defaultSymbols); i++)
{
wsprintf(temp, L"0x%08X (%S)", defaultSymbols[i].address, defaultSymbols[i].name);
int index = ListBox_AddString(listbox,temp);
ListBox_SetItemData(listbox,index,defaultSymbols[i].address);
}
2012-11-01 16:19:01 +01:00
2013-11-27 13:33:30 +01:00
for (auto it = data.begin(), end = data.end(); it != end; ++it)
{
const DataEntry& entry = it->second;
const char* name = GetLabelName(it->first);
2012-11-01 16:19:01 +01:00
2013-11-27 13:33:30 +01:00
if (name != NULL)
wsprintf(temp, L"%S", name);
else
wsprintf(temp, L"0x%08X", it->first);
2012-11-01 16:19:01 +01:00
2013-11-27 13:33:30 +01:00
int index = ListBox_AddString(listbox,temp);
ListBox_SetItemData(listbox,index,it->first);
}
2012-11-01 16:19:01 +01:00
}
2013-11-27 13:33:30 +01:00
break;
}
2012-11-01 16:19:01 +01:00
2013-11-27 13:33:30 +01:00
SendMessage(listbox, WM_SETREDRAW, TRUE, 0);
RedrawWindow(listbox, NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
}
#endif