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