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