CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/Core/Debugger/SymbolMap.cpp
Views: 1401
1
// Copyright (c) 2012- PPSSPP Project.
2
3
// This program is free software: you can redistribute it and/or modify
4
// it under the terms of the GNU General Public License as published by
5
// the Free Software Foundation, version 2.0 or later versions.
6
7
// This program is distributed in the hope that it will be useful,
8
// but WITHOUT ANY WARRANTY; without even the implied warranty of
9
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
// GNU General Public License 2.0 for more details.
11
12
// A copy of the GPL 2.0 should have been included with the program.
13
// If not, see http://www.gnu.org/licenses/
14
15
// Official git repository and contact information can be found at
16
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17
18
// These functions tends to be slow in debug mode.
19
// Comment this out if debugging the symbol map itself.
20
#if defined(_MSC_VER) && defined(_DEBUG)
21
#pragma optimize("gty", on)
22
#endif
23
24
#include "ppsspp_config.h"
25
#ifdef _WIN32
26
#include "Common/CommonWindows.h"
27
#include <WindowsX.h>
28
#else
29
#include <unistd.h>
30
#endif
31
32
#include <algorithm>
33
#include <memory>
34
#ifndef NO_ARMIPS
35
#include <string_view>
36
#endif
37
#include <unordered_map>
38
39
#include "zlib.h"
40
41
#include "Common/CommonTypes.h"
42
#include "Common/Data/Encoding/Utf8.h"
43
#include "Common/Log.h"
44
#include "Common/File/FileUtil.h"
45
#include "Common/StringUtils.h"
46
#include "Core/MemMap.h"
47
#include "Core/Debugger/SymbolMap.h"
48
49
#ifndef NO_ARMIPS
50
#include "ext/armips/Core/Assembler.h"
51
#else
52
struct Identifier {
53
explicit Identifier() {}
54
explicit Identifier(const std::string &s) {}
55
};
56
57
struct LabelDefinition {
58
Identifier name;
59
int64_t value;
60
};
61
#endif
62
63
SymbolMap *g_symbolMap;
64
65
void SymbolMap::SortSymbols() {
66
std::lock_guard<std::recursive_mutex> guard(lock_);
67
68
AssignFunctionIndices();
69
}
70
71
void SymbolMap::Clear() {
72
std::lock_guard<std::recursive_mutex> guard(lock_);
73
functions.clear();
74
labels.clear();
75
data.clear();
76
activeFunctions.clear();
77
activeLabels.clear();
78
activeData.clear();
79
activeModuleEnds.clear();
80
modules.clear();
81
activeNeedUpdate_ = false;
82
}
83
84
bool SymbolMap::LoadSymbolMap(const Path &filename) {
85
Clear(); // let's not recurse the lock
86
87
std::lock_guard<std::recursive_mutex> guard(lock_);
88
89
// TODO(scoped): Use gzdopen instead.
90
91
#if defined(_WIN32) && defined(UNICODE)
92
gzFile f = gzopen_w(filename.ToWString().c_str(), "r");
93
#else
94
gzFile f = gzopen(filename.c_str(), "r");
95
#endif
96
97
if (f == Z_NULL)
98
return false;
99
100
//char temp[256];
101
//fgets(temp,255,f); //.text section layout
102
//fgets(temp,255,f); // Starting Virtual
103
//fgets(temp,255,f); // address Size address
104
//fgets(temp,255,f); // -----------------------
105
106
bool started = false;
107
bool hasModules = false;
108
109
while (!gzeof(f)) {
110
char line[512], temp[256] = {0};
111
char *p = gzgets(f, line, 512);
112
if (p == NULL)
113
break;
114
115
// Chop any newlines off.
116
for (size_t i = strlen(line) - 1; i > 0; i--) {
117
if (line[i] == '\r' || line[i] == '\n') {
118
line[i] = '\0';
119
}
120
}
121
122
if (strlen(line) < 4 || sscanf(line, "%255s", temp) != 1)
123
continue;
124
125
if (strcmp(temp,"UNUSED")==0) continue;
126
if (strcmp(temp,".text")==0) {started=true;continue;};
127
if (strcmp(temp,".init")==0) {started=true;continue;};
128
if (strcmp(temp,"Starting")==0) continue;
129
if (strcmp(temp,"extab")==0) continue;
130
if (strcmp(temp,".ctors")==0) break;
131
if (strcmp(temp,".dtors")==0) break;
132
if (strcmp(temp,".rodata")==0) continue;
133
if (strcmp(temp,".data")==0) continue;
134
if (strcmp(temp,".sbss")==0) continue;
135
if (strcmp(temp,".sdata")==0) continue;
136
if (strcmp(temp,".sdata2")==0) continue;
137
if (strcmp(temp,"address")==0) continue;
138
if (strcmp(temp,"-----------------------")==0) continue;
139
if (strcmp(temp,".sbss2")==0) break;
140
if (temp[1]==']') continue;
141
142
if (!started) continue;
143
144
u32 address = -1, size = 0, vaddress = -1;
145
int moduleIndex = 0;
146
int typeInt = ST_NONE;
147
SymbolType type;
148
char name[128] = {0};
149
150
if (sscanf(line, ".module %x %08x %08x %127c", (unsigned int *)&moduleIndex, &address, &size, name) >= 3) {
151
// Found a module definition.
152
ModuleEntry mod;
153
mod.index = moduleIndex;
154
strcpy(mod.name, name);
155
mod.start = address;
156
mod.size = size;
157
modules.push_back(mod);
158
hasModules = true;
159
continue;
160
}
161
162
int matched = sscanf(line, "%08x %08x %x %i %127c", &address, &size, &vaddress, &typeInt, name);
163
if (matched < 1)
164
continue;
165
type = (SymbolType) typeInt;
166
if (!hasModules) {
167
if (!Memory::IsValidAddress(vaddress)) {
168
ERROR_LOG(Log::Loader, "Invalid address in symbol file: %08x (%s)", vaddress, name);
169
continue;
170
}
171
} else {
172
// The 3rd field is now used for the module index.
173
moduleIndex = vaddress;
174
vaddress = GetModuleAbsoluteAddr(address, moduleIndex);
175
if (!Memory::IsValidAddress(vaddress)) {
176
ERROR_LOG(Log::Loader, "Invalid address in symbol file: %08x (%s)", vaddress, name);
177
continue;
178
}
179
}
180
181
if (type == ST_DATA && size == 0)
182
size = 4;
183
184
// Ignore syscalls, will be recognized from stubs.
185
// Note: it's still useful to save these for grepping and importing into other tools.
186
if (strncmp(name, "zz_sce", 6) == 0)
187
continue;
188
// Also ignore unresolved imports, which will similarly be replaced.
189
if (strncmp(name, "zz_[UNK", 7) == 0)
190
continue;
191
192
if (!strcmp(name, ".text") || !strcmp(name, ".init") || strlen(name) <= 1) {
193
194
} else {
195
switch (type)
196
{
197
case ST_FUNCTION:
198
AddFunction(name, vaddress, size, moduleIndex);
199
break;
200
case ST_DATA:
201
AddData(vaddress,size,DATATYPE_BYTE, moduleIndex);
202
if (name[0] != 0)
203
AddLabel(name, vaddress, moduleIndex);
204
break;
205
case ST_NONE:
206
case ST_ALL:
207
// Shouldn't be possible.
208
break;
209
}
210
}
211
}
212
gzclose(f);
213
SortSymbols();
214
return started;
215
}
216
217
bool SymbolMap::SaveSymbolMap(const Path &filename) const {
218
std::lock_guard<std::recursive_mutex> guard(lock_);
219
220
// Don't bother writing a blank file.
221
if (!File::Exists(filename) && functions.empty() && data.empty()) {
222
return true;
223
}
224
225
// TODO(scoped): Use gzdopen
226
#if defined(_WIN32) && defined(UNICODE)
227
gzFile f = gzopen_w(filename.ToWString().c_str(), "w9");
228
#else
229
gzFile f = gzopen(filename.c_str(), "w9");
230
#endif
231
232
if (f == Z_NULL)
233
return false;
234
235
gzprintf(f, ".text\n");
236
237
for (auto it = modules.begin(), end = modules.end(); it != end; ++it) {
238
const ModuleEntry &mod = *it;
239
gzprintf(f, ".module %x %08x %08x %s\n", mod.index, mod.start, mod.size, mod.name);
240
}
241
242
for (auto it = functions.begin(), end = functions.end(); it != end; ++it) {
243
const FunctionEntry& e = it->second;
244
gzprintf(f, "%08x %08x %x %i %s\n", e.start, e.size, e.module, ST_FUNCTION, GetLabelNameRel(e.start, e.module));
245
}
246
247
for (auto it = data.begin(), end = data.end(); it != end; ++it) {
248
const DataEntry& e = it->second;
249
gzprintf(f, "%08x %08x %x %i %s\n", e.start, e.size, e.module, ST_DATA, GetLabelNameRel(e.start, e.module));
250
}
251
gzclose(f);
252
return true;
253
}
254
255
bool SymbolMap::LoadNocashSym(const Path &filename) {
256
std::lock_guard<std::recursive_mutex> guard(lock_);
257
FILE *f = File::OpenCFile(filename, "r");
258
if (!f)
259
return false;
260
261
while (!feof(f)) {
262
char line[256], value[256] = {0};
263
char *p = fgets(line, 256, f);
264
if (p == NULL)
265
break;
266
267
u32 address;
268
if (sscanf(line, "%08X %255s", &address, value) != 2)
269
continue;
270
if (address == 0 && strcmp(value, "0") == 0)
271
continue;
272
273
if (value[0] == '.') {
274
// data directives
275
char* s = strchr(value, ':');
276
if (s != NULL) {
277
*s = 0;
278
279
u32 size = 0;
280
if (sscanf(s + 1, "%04X", &size) != 1)
281
continue;
282
283
if (strcasecmp(value, ".byt") == 0) {
284
AddData(address, size, DATATYPE_BYTE, 0);
285
} else if (strcasecmp(value, ".wrd") == 0) {
286
AddData(address, size, DATATYPE_HALFWORD, 0);
287
} else if (strcasecmp(value, ".dbl") == 0) {
288
AddData(address, size, DATATYPE_WORD, 0);
289
} else if (strcasecmp(value, ".asc") == 0) {
290
AddData(address, size, DATATYPE_ASCII, 0);
291
}
292
}
293
} else { // labels
294
unsigned int size = 1;
295
char* seperator = strchr(value, ',');
296
if (seperator != NULL) {
297
*seperator = 0;
298
sscanf(seperator+1,"%08X",&size);
299
}
300
301
if (size != 1) {
302
AddFunction(value, address,size, 0);
303
} else {
304
AddLabel(value, address, 0);
305
}
306
}
307
}
308
309
fclose(f);
310
return true;
311
}
312
313
void SymbolMap::SaveNocashSym(const Path &filename) const {
314
std::lock_guard<std::recursive_mutex> guard(lock_);
315
316
// Don't bother writing a blank file.
317
if (!File::Exists(filename) && functions.empty() && data.empty()) {
318
return;
319
}
320
321
FILE* f = File::OpenCFile(filename, "w");
322
if (f == NULL)
323
return;
324
325
// only write functions, the rest isn't really interesting
326
for (auto it = functions.begin(), end = functions.end(); it != end; ++it) {
327
const FunctionEntry& e = it->second;
328
fprintf(f, "%08X %s,%04X\n", GetModuleAbsoluteAddr(e.start,e.module),GetLabelNameRel(e.start, e.module), e.size);
329
}
330
331
fclose(f);
332
}
333
334
SymbolType SymbolMap::GetSymbolType(u32 address) {
335
if (activeNeedUpdate_)
336
UpdateActiveSymbols();
337
338
std::lock_guard<std::recursive_mutex> guard(lock_);
339
if (activeFunctions.find(address) != activeFunctions.end())
340
return ST_FUNCTION;
341
if (activeData.find(address) != activeData.end())
342
return ST_DATA;
343
return ST_NONE;
344
}
345
346
bool SymbolMap::GetSymbolInfo(SymbolInfo *info, u32 address, SymbolType symmask) {
347
u32 functionAddress = INVALID_ADDRESS;
348
u32 dataAddress = INVALID_ADDRESS;
349
350
if (symmask & ST_FUNCTION) {
351
functionAddress = GetFunctionStart(address);
352
353
// If both are found, we always return the function, so just do that early.
354
if (functionAddress != INVALID_ADDRESS) {
355
if (info != NULL) {
356
info->type = ST_FUNCTION;
357
info->address = functionAddress;
358
info->size = GetFunctionSize(functionAddress);
359
info->moduleAddress = GetFunctionModuleAddress(functionAddress);
360
}
361
362
return true;
363
}
364
}
365
366
if (symmask & ST_DATA) {
367
dataAddress = GetDataStart(address);
368
369
if (dataAddress != INVALID_ADDRESS) {
370
if (info != NULL) {
371
info->type = ST_DATA;
372
info->address = dataAddress;
373
info->size = GetDataSize(dataAddress);
374
info->moduleAddress = GetDataModuleAddress(dataAddress);
375
}
376
377
return true;
378
}
379
}
380
381
return false;
382
}
383
384
u32 SymbolMap::GetNextSymbolAddress(u32 address, SymbolType symmask) {
385
if (activeNeedUpdate_)
386
UpdateActiveSymbols();
387
388
std::lock_guard<std::recursive_mutex> guard(lock_);
389
const auto functionEntry = symmask & ST_FUNCTION ? activeFunctions.upper_bound(address) : activeFunctions.end();
390
const auto dataEntry = symmask & ST_DATA ? activeData.upper_bound(address) : activeData.end();
391
392
if (functionEntry == activeFunctions.end() && dataEntry == activeData.end())
393
return INVALID_ADDRESS;
394
395
u32 funcAddress = (functionEntry != activeFunctions.end()) ? functionEntry->first : 0xFFFFFFFF;
396
u32 dataAddress = (dataEntry != activeData.end()) ? dataEntry->first : 0xFFFFFFFF;
397
398
if (funcAddress <= dataAddress)
399
return funcAddress;
400
else
401
return dataAddress;
402
}
403
404
std::string SymbolMap::GetDescription(unsigned int address) {
405
std::lock_guard<std::recursive_mutex> guard(lock_);
406
const char* labelName = NULL;
407
408
u32 funcStart = GetFunctionStart(address);
409
if (funcStart != INVALID_ADDRESS) {
410
labelName = GetLabelName(funcStart);
411
} else {
412
u32 dataStart = GetDataStart(address);
413
if (dataStart != INVALID_ADDRESS)
414
labelName = GetLabelName(dataStart);
415
}
416
417
if (labelName != NULL)
418
return labelName;
419
420
char descriptionTemp[256];
421
sprintf(descriptionTemp, "(%08x)", address);
422
return descriptionTemp;
423
}
424
425
std::vector<SymbolEntry> SymbolMap::GetAllSymbols(SymbolType symmask) {
426
if (activeNeedUpdate_)
427
UpdateActiveSymbols();
428
429
std::vector<SymbolEntry> result;
430
431
if (symmask & ST_FUNCTION) {
432
std::lock_guard<std::recursive_mutex> guard(lock_);
433
for (auto it = activeFunctions.begin(); it != activeFunctions.end(); it++) {
434
SymbolEntry entry;
435
entry.address = it->first;
436
entry.size = GetFunctionSize(entry.address);
437
const char* name = GetLabelName(entry.address);
438
if (name != NULL)
439
entry.name = name;
440
result.push_back(entry);
441
}
442
}
443
444
if (symmask & ST_DATA) {
445
std::lock_guard<std::recursive_mutex> guard(lock_);
446
for (auto it = activeData.begin(); it != activeData.end(); it++) {
447
SymbolEntry entry;
448
entry.address = it->first;
449
entry.size = GetDataSize(entry.address);
450
const char* name = GetLabelName(entry.address);
451
if (name != NULL)
452
entry.name = name;
453
result.push_back(entry);
454
}
455
}
456
457
return result;
458
}
459
460
void SymbolMap::AddModule(const char *name, u32 address, u32 size) {
461
std::lock_guard<std::recursive_mutex> guard(lock_);
462
463
for (auto it = modules.begin(), end = modules.end(); it != end; ++it) {
464
if (!strcmp(it->name, name)) {
465
// Just reactivate that one.
466
it->start = address;
467
it->size = size;
468
activeModuleEnds.emplace(it->start + it->size, *it);
469
activeNeedUpdate_ = true;
470
return;
471
}
472
}
473
474
ModuleEntry mod;
475
truncate_cpy(mod.name, name);
476
mod.start = address;
477
mod.size = size;
478
mod.index = (int)modules.size() + 1;
479
480
modules.push_back(mod);
481
activeModuleEnds.emplace(mod.start + mod.size, mod);
482
activeNeedUpdate_ = true;
483
}
484
485
void SymbolMap::UnloadModule(u32 address, u32 size) {
486
std::lock_guard<std::recursive_mutex> guard(lock_);
487
activeModuleEnds.erase(address + size);
488
activeNeedUpdate_ = true;
489
}
490
491
u32 SymbolMap::GetModuleRelativeAddr(u32 address, int moduleIndex) const {
492
std::lock_guard<std::recursive_mutex> guard(lock_);
493
if (moduleIndex == -1) {
494
moduleIndex = GetModuleIndex(address);
495
}
496
497
for (auto it = modules.begin(), end = modules.end(); it != end; ++it) {
498
if (it->index == moduleIndex) {
499
return address - it->start;
500
}
501
}
502
return address;
503
}
504
505
u32 SymbolMap::GetModuleAbsoluteAddr(u32 relative, int moduleIndex) const {
506
std::lock_guard<std::recursive_mutex> guard(lock_);
507
for (auto it = modules.begin(), end = modules.end(); it != end; ++it) {
508
if (it->index == moduleIndex) {
509
return it->start + relative;
510
}
511
}
512
return relative;
513
}
514
515
int SymbolMap::GetModuleIndex(u32 address) const {
516
std::lock_guard<std::recursive_mutex> guard(lock_);
517
auto iter = activeModuleEnds.upper_bound(address);
518
if (iter == activeModuleEnds.end())
519
return -1;
520
return iter->second.index;
521
}
522
523
bool SymbolMap::IsModuleActive(int moduleIndex) {
524
if (moduleIndex == 0) {
525
return true;
526
}
527
528
std::lock_guard<std::recursive_mutex> guard(lock_);
529
for (auto it = activeModuleEnds.begin(), end = activeModuleEnds.end(); it != end; ++it) {
530
if (it->second.index == moduleIndex) {
531
return true;
532
}
533
}
534
return false;
535
}
536
537
std::vector<LoadedModuleInfo> SymbolMap::getAllModules() const {
538
std::lock_guard<std::recursive_mutex> guard(lock_);
539
540
std::vector<LoadedModuleInfo> result;
541
for (size_t i = 0; i < modules.size(); i++) {
542
LoadedModuleInfo m;
543
m.name = modules[i].name;
544
m.address = modules[i].start;
545
m.size = modules[i].size;
546
547
u32 key = modules[i].start + modules[i].size;
548
m.active = activeModuleEnds.find(key) != activeModuleEnds.end();
549
550
result.push_back(m);
551
}
552
553
return result;
554
}
555
556
void SymbolMap::AddFunction(const char* name, u32 address, u32 size, int moduleIndex) {
557
std::lock_guard<std::recursive_mutex> guard(lock_);
558
559
if (moduleIndex == -1) {
560
moduleIndex = GetModuleIndex(address);
561
} else if (moduleIndex == 0) {
562
sawUnknownModule = true;
563
}
564
565
// Is there an existing one?
566
u32 relAddress = GetModuleRelativeAddr(address, moduleIndex);
567
auto symbolKey = std::make_pair(moduleIndex, relAddress);
568
auto existing = functions.find(symbolKey);
569
if (sawUnknownModule && existing == functions.end()) {
570
// Fall back: maybe it's got moduleIndex = 0.
571
existing = functions.find(std::make_pair(0, address));
572
}
573
574
if (existing != functions.end()) {
575
existing->second.size = size;
576
if (existing->second.module != moduleIndex) {
577
FunctionEntry func = existing->second;
578
func.start = relAddress;
579
func.module = moduleIndex;
580
functions.erase(existing);
581
functions[symbolKey] = func;
582
}
583
584
// Refresh the active item if it exists.
585
auto active = activeFunctions.find(address);
586
if (active != activeFunctions.end() && active->second.module == moduleIndex) {
587
activeFunctions.erase(active);
588
activeFunctions.emplace(address, existing->second);
589
}
590
} else {
591
FunctionEntry func;
592
func.start = relAddress;
593
func.size = size;
594
func.index = (int)functions.size();
595
func.module = moduleIndex;
596
functions[symbolKey] = func;
597
598
if (IsModuleActive(moduleIndex)) {
599
activeFunctions.emplace(address, func);
600
}
601
}
602
603
AddLabel(name, address, moduleIndex);
604
}
605
606
u32 SymbolMap::GetFunctionStart(u32 address) {
607
if (activeNeedUpdate_)
608
UpdateActiveSymbols();
609
610
std::lock_guard<std::recursive_mutex> guard(lock_);
611
auto it = activeFunctions.upper_bound(address);
612
if (it == activeFunctions.end()) {
613
// check last element
614
auto rit = activeFunctions.rbegin();
615
if (rit != activeFunctions.rend()) {
616
u32 start = rit->first;
617
u32 size = rit->second.size;
618
if (start <= address && start+size > address)
619
return start;
620
}
621
// otherwise there's no function that contains this address
622
return INVALID_ADDRESS;
623
}
624
625
if (it != activeFunctions.begin()) {
626
it--;
627
u32 start = it->first;
628
u32 size = it->second.size;
629
if (start <= address && start+size > address)
630
return start;
631
}
632
633
return INVALID_ADDRESS;
634
}
635
636
u32 SymbolMap::FindPossibleFunctionAtAfter(u32 address) {
637
if (activeNeedUpdate_)
638
UpdateActiveSymbols();
639
640
std::lock_guard<std::recursive_mutex> guard(lock_);
641
auto it = activeFunctions.lower_bound(address);
642
if (it == activeFunctions.end()) {
643
return (u32)-1;
644
}
645
return it->first;
646
}
647
648
u32 SymbolMap::GetFunctionSize(u32 startAddress) {
649
if (activeNeedUpdate_) {
650
std::lock_guard<std::recursive_mutex> guard(lock_);
651
652
// This is common, from the jit. Direct lookup is faster than updating active symbols.
653
auto mod = activeModuleEnds.lower_bound(startAddress);
654
std::pair<int, u32> funcKey;
655
if (mod == activeModuleEnds.end()) {
656
// Could still be mod 0, backwards compatibility.
657
if (!sawUnknownModule)
658
return INVALID_ADDRESS;
659
funcKey.first = 0;
660
funcKey.second = startAddress;
661
} else {
662
if (mod->second.start > startAddress)
663
return INVALID_ADDRESS;
664
funcKey.first = mod->second.index;
665
funcKey.second = startAddress - mod->second.start;
666
}
667
668
auto func = functions.find(funcKey);
669
if (func == functions.end())
670
return INVALID_ADDRESS;
671
672
return func->second.size;
673
}
674
675
std::lock_guard<std::recursive_mutex> guard(lock_);
676
auto it = activeFunctions.find(startAddress);
677
if (it == activeFunctions.end())
678
return INVALID_ADDRESS;
679
680
return it->second.size;
681
}
682
683
u32 SymbolMap::GetFunctionModuleAddress(u32 startAddress) {
684
if (activeNeedUpdate_)
685
UpdateActiveSymbols();
686
687
std::lock_guard<std::recursive_mutex> guard(lock_);
688
auto it = activeFunctions.find(startAddress);
689
if (it == activeFunctions.end())
690
return INVALID_ADDRESS;
691
692
return GetModuleAbsoluteAddr(0, it->second.module);
693
}
694
695
int SymbolMap::GetFunctionNum(u32 address) {
696
if (activeNeedUpdate_)
697
UpdateActiveSymbols();
698
699
std::lock_guard<std::recursive_mutex> guard(lock_);
700
u32 start = GetFunctionStart(address);
701
if (start == INVALID_ADDRESS)
702
return INVALID_ADDRESS;
703
704
auto it = activeFunctions.find(start);
705
if (it == activeFunctions.end())
706
return INVALID_ADDRESS;
707
708
return it->second.index;
709
}
710
711
void SymbolMap::AssignFunctionIndices() {
712
std::lock_guard<std::recursive_mutex> guard(lock_);
713
int index = 0;
714
for (auto mod = activeModuleEnds.begin(), modend = activeModuleEnds.end(); mod != modend; ++mod) {
715
int moduleIndex = mod->second.index;
716
auto begin = functions.lower_bound(std::make_pair(moduleIndex, 0));
717
auto end = functions.upper_bound(std::make_pair(moduleIndex, 0xFFFFFFFF));
718
for (auto it = begin; it != end; ++it) {
719
it->second.index = index++;
720
}
721
}
722
}
723
724
void SymbolMap::UpdateActiveSymbols() {
725
// return; (slow in debug mode)
726
std::lock_guard<std::recursive_mutex> guard(lock_);
727
728
activeFunctions.clear();
729
activeLabels.clear();
730
activeData.clear();
731
732
// On startup and shutdown, we can skip the rest. Tiny optimization.
733
if (activeModuleEnds.empty() || (functions.empty() && labels.empty() && data.empty())) {
734
return;
735
}
736
737
std::unordered_map<int, u32> activeModuleIndexes;
738
for (auto it = activeModuleEnds.begin(), end = activeModuleEnds.end(); it != end; ++it) {
739
activeModuleIndexes[it->second.index] = it->second.start;
740
}
741
742
for (auto it = functions.begin(), end = functions.end(); it != end; ++it) {
743
const auto mod = activeModuleIndexes.find(it->second.module);
744
if (it->second.module == 0) {
745
activeFunctions.emplace(it->second.start, it->second);
746
} else if (mod != activeModuleIndexes.end()) {
747
activeFunctions.emplace(mod->second + it->second.start, it->second);
748
}
749
}
750
751
for (auto it = labels.begin(), end = labels.end(); it != end; ++it) {
752
const auto mod = activeModuleIndexes.find(it->second.module);
753
if (it->second.module == 0) {
754
activeLabels.emplace(it->second.addr, it->second);
755
} else if (mod != activeModuleIndexes.end()) {
756
activeLabels.emplace(mod->second + it->second.addr, it->second);
757
}
758
}
759
760
for (auto it = data.begin(), end = data.end(); it != end; ++it) {
761
const auto mod = activeModuleIndexes.find(it->second.module);
762
if (it->second.module == 0) {
763
activeData.emplace(it->second.start, it->second);
764
} else if (mod != activeModuleIndexes.end()) {
765
activeData.emplace(mod->second + it->second.start, it->second);
766
}
767
}
768
769
AssignFunctionIndices();
770
activeNeedUpdate_ = false;
771
}
772
773
bool SymbolMap::SetFunctionSize(u32 startAddress, u32 newSize) {
774
if (activeNeedUpdate_)
775
UpdateActiveSymbols();
776
777
std::lock_guard<std::recursive_mutex> guard(lock_);
778
779
auto funcInfo = activeFunctions.find(startAddress);
780
if (funcInfo != activeFunctions.end()) {
781
auto symbolKey = std::make_pair(funcInfo->second.module, funcInfo->second.start);
782
auto func = functions.find(symbolKey);
783
if (func != functions.end()) {
784
func->second.size = newSize;
785
activeFunctions.erase(funcInfo);
786
activeFunctions.emplace(startAddress, func->second);
787
}
788
}
789
790
// TODO: check for overlaps
791
return true;
792
}
793
794
bool SymbolMap::RemoveFunction(u32 startAddress, bool removeName) {
795
if (activeNeedUpdate_)
796
UpdateActiveSymbols();
797
798
std::lock_guard<std::recursive_mutex> guard(lock_);
799
800
auto it = activeFunctions.find(startAddress);
801
if (it == activeFunctions.end())
802
return false;
803
804
auto symbolKey = std::make_pair(it->second.module, it->second.start);
805
auto it2 = functions.find(symbolKey);
806
if (it2 != functions.end()) {
807
functions.erase(it2);
808
}
809
activeFunctions.erase(it);
810
811
if (removeName) {
812
auto labelIt = activeLabels.find(startAddress);
813
if (labelIt != activeLabels.end()) {
814
symbolKey = std::make_pair(labelIt->second.module, labelIt->second.addr);
815
auto labelIt2 = labels.find(symbolKey);
816
if (labelIt2 != labels.end()) {
817
labels.erase(labelIt2);
818
}
819
activeLabels.erase(labelIt);
820
}
821
}
822
823
return true;
824
}
825
826
void SymbolMap::AddLabel(const char* name, u32 address, int moduleIndex) {
827
std::lock_guard<std::recursive_mutex> guard(lock_);
828
829
if (moduleIndex == -1) {
830
moduleIndex = GetModuleIndex(address);
831
} else if (moduleIndex == 0) {
832
sawUnknownModule = true;
833
}
834
835
// Is there an existing one?
836
u32 relAddress = GetModuleRelativeAddr(address, moduleIndex);
837
auto symbolKey = std::make_pair(moduleIndex, relAddress);
838
auto existing = labels.find(symbolKey);
839
if (sawUnknownModule && existing == labels.end()) {
840
// Fall back: maybe it's got moduleIndex = 0.
841
existing = labels.find(std::make_pair(0, address));
842
}
843
844
if (existing != labels.end()) {
845
// We leave an existing label alone, rather than overwriting.
846
// But we'll still upgrade it to the correct module / relative address.
847
if (existing->second.module != moduleIndex) {
848
LabelEntry label = existing->second;
849
label.addr = relAddress;
850
label.module = moduleIndex;
851
labels.erase(existing);
852
labels[symbolKey] = label;
853
854
// Refresh the active item if it exists.
855
auto active = activeLabels.find(address);
856
if (active != activeLabels.end() && active->second.module == moduleIndex) {
857
activeLabels.erase(active);
858
activeLabels.emplace(address, label);
859
}
860
}
861
} else {
862
LabelEntry label;
863
label.addr = relAddress;
864
label.module = moduleIndex;
865
truncate_cpy(label.name, name);
866
867
labels[symbolKey] = label;
868
if (IsModuleActive(moduleIndex)) {
869
activeLabels.emplace(address, label);
870
}
871
}
872
}
873
874
void SymbolMap::SetLabelName(const char* name, u32 address) {
875
if (activeNeedUpdate_)
876
UpdateActiveSymbols();
877
878
std::lock_guard<std::recursive_mutex> guard(lock_);
879
auto labelInfo = activeLabels.find(address);
880
if (labelInfo == activeLabels.end()) {
881
AddLabel(name, address);
882
} else {
883
auto symbolKey = std::make_pair(labelInfo->second.module, labelInfo->second.addr);
884
auto label = labels.find(symbolKey);
885
if (label != labels.end()) {
886
truncate_cpy(label->second.name, name);
887
label->second.name[127] = 0;
888
889
// Refresh the active item if it exists.
890
auto active = activeLabels.find(address);
891
if (active != activeLabels.end() && active->second.module == label->second.module) {
892
activeLabels.erase(active);
893
activeLabels.emplace(address, label->second);
894
}
895
}
896
}
897
}
898
899
const char *SymbolMap::GetLabelName(u32 address) {
900
if (activeNeedUpdate_)
901
UpdateActiveSymbols();
902
903
std::lock_guard<std::recursive_mutex> guard(lock_);
904
auto it = activeLabels.find(address);
905
if (it == activeLabels.end())
906
return NULL;
907
908
return it->second.name;
909
}
910
911
const char *SymbolMap::GetLabelNameRel(u32 relAddress, int moduleIndex) const {
912
std::lock_guard<std::recursive_mutex> guard(lock_);
913
auto it = labels.find(std::make_pair(moduleIndex, relAddress));
914
if (it == labels.end())
915
return NULL;
916
917
return it->second.name;
918
}
919
920
std::string SymbolMap::GetLabelString(u32 address) {
921
std::lock_guard<std::recursive_mutex> guard(lock_);
922
const char *label = GetLabelName(address);
923
if (label == NULL)
924
return "";
925
return label;
926
}
927
928
bool SymbolMap::GetLabelValue(const char* name, u32& dest) {
929
if (activeNeedUpdate_)
930
UpdateActiveSymbols();
931
932
std::lock_guard<std::recursive_mutex> guard(lock_);
933
for (auto it = activeLabels.begin(); it != activeLabels.end(); it++) {
934
if (strcasecmp(name, it->second.name) == 0) {
935
dest = it->first;
936
return true;
937
}
938
}
939
940
return false;
941
}
942
943
void SymbolMap::AddData(u32 address, u32 size, DataType type, int moduleIndex) {
944
std::lock_guard<std::recursive_mutex> guard(lock_);
945
946
if (moduleIndex == -1) {
947
moduleIndex = GetModuleIndex(address);
948
} else if (moduleIndex == 0) {
949
sawUnknownModule = true;
950
}
951
952
// Is there an existing one?
953
u32 relAddress = GetModuleRelativeAddr(address, moduleIndex);
954
auto symbolKey = std::make_pair(moduleIndex, relAddress);
955
auto existing = data.find(symbolKey);
956
if (sawUnknownModule && existing == data.end()) {
957
// Fall back: maybe it's got moduleIndex = 0.
958
existing = data.find(std::make_pair(0, address));
959
}
960
961
if (existing != data.end()) {
962
existing->second.size = size;
963
existing->second.type = type;
964
if (existing->second.module != moduleIndex) {
965
DataEntry entry = existing->second;
966
entry.module = moduleIndex;
967
entry.start = relAddress;
968
data.erase(existing);
969
data[symbolKey] = entry;
970
}
971
972
// Refresh the active item if it exists.
973
auto active = activeData.find(address);
974
if (active != activeData.end() && active->second.module == moduleIndex) {
975
activeData.erase(active);
976
activeData.emplace(address, existing->second);
977
}
978
} else {
979
DataEntry entry;
980
entry.start = relAddress;
981
entry.size = size;
982
entry.type = type;
983
entry.module = moduleIndex;
984
985
data[symbolKey] = entry;
986
if (IsModuleActive(moduleIndex)) {
987
activeData.emplace(address, entry);
988
}
989
}
990
}
991
992
u32 SymbolMap::GetDataStart(u32 address) {
993
if (activeNeedUpdate_)
994
UpdateActiveSymbols();
995
996
std::lock_guard<std::recursive_mutex> guard(lock_);
997
auto it = activeData.upper_bound(address);
998
if (it == activeData.end())
999
{
1000
// check last element
1001
auto rit = activeData.rbegin();
1002
1003
if (rit != activeData.rend())
1004
{
1005
u32 start = rit->first;
1006
u32 size = rit->second.size;
1007
if (start <= address && start+size > address)
1008
return start;
1009
}
1010
// otherwise there's no data that contains this address
1011
return INVALID_ADDRESS;
1012
}
1013
1014
if (it != activeData.begin()) {
1015
it--;
1016
u32 start = it->first;
1017
u32 size = it->second.size;
1018
if (start <= address && start+size > address)
1019
return start;
1020
}
1021
1022
return INVALID_ADDRESS;
1023
}
1024
1025
u32 SymbolMap::GetDataSize(u32 startAddress) {
1026
if (activeNeedUpdate_)
1027
UpdateActiveSymbols();
1028
1029
std::lock_guard<std::recursive_mutex> guard(lock_);
1030
auto it = activeData.find(startAddress);
1031
if (it == activeData.end())
1032
return INVALID_ADDRESS;
1033
return it->second.size;
1034
}
1035
1036
u32 SymbolMap::GetDataModuleAddress(u32 startAddress) {
1037
if (activeNeedUpdate_)
1038
UpdateActiveSymbols();
1039
1040
std::lock_guard<std::recursive_mutex> guard(lock_);
1041
auto it = activeData.find(startAddress);
1042
if (it == activeData.end())
1043
return INVALID_ADDRESS;
1044
return GetModuleAbsoluteAddr(0, it->second.module);
1045
}
1046
1047
DataType SymbolMap::GetDataType(u32 startAddress) {
1048
if (activeNeedUpdate_)
1049
UpdateActiveSymbols();
1050
1051
std::lock_guard<std::recursive_mutex> guard(lock_);
1052
auto it = activeData.find(startAddress);
1053
if (it == activeData.end())
1054
return DATATYPE_NONE;
1055
return it->second.type;
1056
}
1057
1058
void SymbolMap::GetLabels(std::vector<LabelDefinition> &dest) {
1059
if (activeNeedUpdate_)
1060
UpdateActiveSymbols();
1061
1062
std::lock_guard<std::recursive_mutex> guard(lock_);
1063
for (auto it = activeLabels.begin(); it != activeLabels.end(); it++) {
1064
LabelDefinition entry;
1065
entry.value = it->first;
1066
std::string name = it->second.name;
1067
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
1068
entry.name = Identifier(name);
1069
dest.push_back(entry);
1070
}
1071
}
1072
1073
#if defined(_WIN32) && !PPSSPP_PLATFORM(UWP)
1074
1075
struct DefaultSymbol {
1076
u32 address;
1077
const char* name;
1078
};
1079
1080
static const DefaultSymbol defaultSymbols[]= {
1081
{ 0x08800000, "User memory" },
1082
{ 0x08804000, "Default load address" },
1083
{ 0x04000000, "VRAM" },
1084
{ 0x88000000, "Kernel memory" },
1085
{ 0x00010000, "Scratchpad" },
1086
};
1087
1088
void SymbolMap::FillSymbolListBox(HWND listbox,SymbolType symType) {
1089
if (activeNeedUpdate_)
1090
UpdateActiveSymbols();
1091
1092
wchar_t temp[256];
1093
std::lock_guard<std::recursive_mutex> guard(lock_);
1094
1095
SendMessage(listbox, WM_SETREDRAW, FALSE, 0);
1096
ListBox_ResetContent(listbox);
1097
1098
switch (symType) {
1099
case ST_FUNCTION:
1100
{
1101
SendMessage(listbox, LB_INITSTORAGE, (WPARAM)activeFunctions.size(), (LPARAM)activeFunctions.size() * 30);
1102
1103
for (auto it = activeFunctions.begin(), end = activeFunctions.end(); it != end; ++it) {
1104
const char* name = GetLabelName(it->first);
1105
if (name != NULL)
1106
wsprintf(temp, L"%S", name);
1107
else
1108
wsprintf(temp, L"0x%08X", it->first);
1109
int index = ListBox_AddString(listbox,temp);
1110
ListBox_SetItemData(listbox,index,it->first);
1111
}
1112
}
1113
break;
1114
1115
case ST_DATA:
1116
{
1117
size_t count = ARRAYSIZE(defaultSymbols)+activeData.size();
1118
SendMessage(listbox, LB_INITSTORAGE, (WPARAM)count, (LPARAM)count * 30);
1119
1120
for (int i = 0; i < ARRAYSIZE(defaultSymbols); i++) {
1121
wsprintf(temp, L"0x%08X (%S)", defaultSymbols[i].address, defaultSymbols[i].name);
1122
int index = ListBox_AddString(listbox,temp);
1123
ListBox_SetItemData(listbox,index,defaultSymbols[i].address);
1124
}
1125
1126
for (auto it = activeData.begin(), end = activeData.end(); it != end; ++it) {
1127
const char* name = GetLabelName(it->first);
1128
1129
if (name != NULL)
1130
wsprintf(temp, L"%S", name);
1131
else
1132
wsprintf(temp, L"0x%08X", it->first);
1133
1134
int index = ListBox_AddString(listbox,temp);
1135
ListBox_SetItemData(listbox,index,it->first);
1136
}
1137
}
1138
break;
1139
}
1140
1141
SendMessage(listbox, WM_SETREDRAW, TRUE, 0);
1142
RedrawWindow(listbox, NULL, NULL, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
1143
}
1144
#endif
1145
1146