Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/Core/Debugger/DisassemblyManager.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
#include "ppsspp_config.h"
19
20
#include <string>
21
#include <algorithm>
22
#include <map>
23
24
#include "ext/xxhash.h"
25
26
#include "Common/CommonTypes.h"
27
#include "Common/Data/Encoding/Utf8.h"
28
#include "Common/Log.h"
29
#include "Common/StringUtils.h"
30
#include "Common/Math/math_util.h"
31
#include "Core/MemMap.h"
32
#include "Core/System.h"
33
#include "Core/MIPS/MIPSDebugInterface.h"
34
#include "Core/MIPS/MIPSCodeUtils.h"
35
#include "Core/MIPS/MIPSTables.h"
36
#include "Core/Debugger/DebugInterface.h"
37
#include "Core/Debugger/SymbolMap.h"
38
#include "Core/Debugger/DisassemblyManager.h"
39
40
DisassemblyManager g_disassemblyManager;
41
42
bool isInInterval(u32 start, u32 size, u32 value) {
43
return start <= value && value <= (start+size-1);
44
}
45
46
bool IsLikelyStringAt(uint32_t addr) {
47
uint32_t maxLen = Memory::ClampValidSizeAt(addr, 128);
48
if (maxLen <= 1)
49
return false;
50
const char *p = Memory::GetCharPointer(addr);
51
// If there's no terminator nearby, let's say no.
52
if (memchr(p, 0, maxLen) == nullptr)
53
return false;
54
55
// Allow tabs and newlines.
56
static constexpr bool validControl[] = {
57
false, false, false, false, false, false, false, false,
58
false, true, true, true, false, true, false, false,
59
false, false, false, false, false, false, false, false,
60
false, false, false, false, false, false, false, false,
61
};
62
63
// Check that there's some bytes before the terminator that look like a string.
64
UTF8 utf(p);
65
if (utf.end())
66
return false;
67
68
char verify[4];
69
while (!utf.end()) {
70
if (utf.invalid())
71
return false;
72
73
int pos = utf.byteIndex();
74
uint32_t c = utf.next();
75
int len = UTF8::encode(verify, c);
76
// Our decoder is a bit lax, so let's verify this is a normal encoding.
77
// This prevents us from trying to output invalid encodings in the debugger.
78
if (memcmp(p + pos, verify, len) != 0 || pos + len != utf.byteIndex())
79
return false;
80
81
if (c < ARRAY_SIZE(validControl) && !validControl[c])
82
return false;
83
if (c > 0x0010FFFF)
84
return false;
85
}
86
87
return true;
88
}
89
90
static HashType computeHash(u32 address, u32 size)
91
{
92
if (!Memory::IsValidAddress(address))
93
return 0;
94
95
size = Memory::ClampValidSizeAt(address, size);
96
#if PPSSPP_ARCH(AMD64)
97
return XXH3_64bits(Memory::GetPointerUnchecked(address), size);
98
#else
99
return XXH3_64bits(Memory::GetPointerUnchecked(address), size) & 0xFFFFFFFF;
100
#endif
101
}
102
103
104
static void parseDisasm(const char *disasm, char *opcode, size_t opcodeSize, char *arguments, size_t argumentsSize, bool insertSymbols) {
105
// copy opcode
106
size_t opcodePos = 0;
107
while (*disasm != 0 && *disasm != '\t' && opcodePos + 1 < opcodeSize) {
108
opcode[opcodePos++] = *disasm++;
109
}
110
opcode[opcodePos] = 0;
111
112
// Otherwise it's a tab, and we skip intentionally.
113
if (*disasm++ == 0) {
114
*arguments = 0;
115
return;
116
}
117
118
const char* jumpAddress = strstr(disasm,"->$");
119
const char* jumpRegister = strstr(disasm,"->");
120
size_t argumentsPos = 0;
121
while (*disasm != 0 && argumentsPos + 1 < argumentsSize) {
122
// parse symbol
123
if (disasm == jumpAddress) {
124
u32 branchTarget = 0;
125
sscanf(disasm+3, "%08x", &branchTarget);
126
const std::string addressSymbol = g_symbolMap->GetLabelString(branchTarget);
127
if (!addressSymbol.empty() && insertSymbols) {
128
argumentsPos += snprintf(&arguments[argumentsPos], argumentsSize - argumentsPos, "%s", addressSymbol.c_str());
129
} else {
130
argumentsPos += snprintf(&arguments[argumentsPos], argumentsSize - argumentsPos, "0x%08X", branchTarget);
131
}
132
133
disasm += 3+8;
134
continue;
135
}
136
137
if (disasm == jumpRegister)
138
disasm += 2;
139
140
if (*disasm == ' ') {
141
disasm++;
142
continue;
143
}
144
arguments[argumentsPos++] = *disasm++;
145
}
146
147
arguments[argumentsPos] = 0;
148
}
149
150
std::map<u32,DisassemblyEntry*>::iterator findDisassemblyEntry(std::map<u32,DisassemblyEntry*>& entries, u32 address, bool exact)
151
{
152
if (exact)
153
return entries.find(address);
154
155
if (entries.size() == 0)
156
return entries.end();
157
158
// find first elem that's >= address
159
auto it = entries.lower_bound(address);
160
if (it != entries.end())
161
{
162
// it may be an exact match
163
if (isInInterval(it->second->getLineAddress(0),it->second->getTotalSize(),address))
164
return it;
165
166
// otherwise it may point to the next
167
if (it != entries.begin())
168
{
169
it--;
170
if (isInInterval(it->second->getLineAddress(0),it->second->getTotalSize(),address))
171
return it;
172
}
173
}
174
175
// check last entry manually
176
auto rit = entries.rbegin();
177
if (isInInterval(rit->second->getLineAddress(0),rit->second->getTotalSize(),address))
178
{
179
return (++rit).base();
180
}
181
182
// no match otherwise
183
return entries.end();
184
}
185
186
void DisassemblyManager::setCpu(DebugInterface *cpu) {
187
_dbg_assert_(cpu);
188
cpu_ = cpu;
189
};
190
191
void DisassemblyManager::analyze(u32 address, u32 size = 1024)
192
{
193
u32 end = address+size;
194
195
address = RoundDownToMultipleOf(address, 4);
196
u32 start = address;
197
198
while (address < end && start <= address)
199
{
200
if (PSP_GetBootState() != BootState::Complete)
201
return;
202
203
std::lock_guard<std::recursive_mutex> guard(entriesLock_);
204
auto it = findDisassemblyEntry(entries, address, false);
205
if (it != entries.end())
206
{
207
DisassemblyEntry* entry = it->second;
208
entry->recheck();
209
address = entry->getLineAddress(0)+entry->getTotalSize();
210
continue;
211
}
212
213
SymbolInfo info;
214
if (!g_symbolMap->GetSymbolInfo(&info,address,ST_ALL))
215
{
216
if (address % 4)
217
{
218
u32 next = std::min<u32>((address+3) & ~3,g_symbolMap->GetNextSymbolAddress(address,ST_ALL));
219
DisassemblyData* data = new DisassemblyData(address,next-address,DATATYPE_BYTE);
220
entries[address] = data;
221
address = next;
222
continue;
223
}
224
225
u32 next = g_symbolMap->GetNextSymbolAddress(address,ST_ALL);
226
227
if ((next % 4) && next != (u32)-1)
228
{
229
u32 alignedNext = next & ~3;
230
231
if (alignedNext != address)
232
{
233
DisassemblyOpcode* opcode = new DisassemblyOpcode(address,(alignedNext-address)/4);
234
entries[address] = opcode;
235
}
236
237
DisassemblyData* data = new DisassemblyData(address,next-alignedNext,DATATYPE_BYTE);
238
entries[alignedNext] = data;
239
} else {
240
DisassemblyOpcode* opcode = new DisassemblyOpcode(address,(next-address)/4);
241
entries[address] = opcode;
242
}
243
244
address = next;
245
continue;
246
}
247
248
switch (info.type)
249
{
250
case ST_FUNCTION:
251
{
252
DisassemblyFunction* function = new DisassemblyFunction(info.address,info.size);
253
entries[info.address] = function;
254
address = info.address+info.size;
255
}
256
break;
257
case ST_DATA:
258
{
259
DisassemblyData* data = new DisassemblyData(info.address,info.size,g_symbolMap->GetDataType(info.address));
260
entries[info.address] = data;
261
address = info.address+info.size;
262
}
263
break;
264
default:
265
break;
266
}
267
}
268
269
}
270
271
std::vector<BranchLine> DisassemblyManager::getBranchLines(u32 start, u32 size)
272
{
273
std::vector<BranchLine> result;
274
275
std::lock_guard<std::recursive_mutex> guard(entriesLock_);
276
auto it = findDisassemblyEntry(entries,start,false);
277
if (it != entries.end())
278
{
279
do
280
{
281
it->second->getBranchLines(start,size,result);
282
it++;
283
} while (it != entries.end() && start+size > it->second->getLineAddress(0));
284
}
285
286
return result;
287
}
288
289
void DisassemblyManager::getLine(u32 address, bool insertSymbols, DisassemblyLineInfo &dest, DebugInterface *cpuDebug)
290
{
291
std::lock_guard<std::recursive_mutex> guard(entriesLock_);
292
auto it = findDisassemblyEntry(entries,address,false);
293
if (it == entries.end()) {
294
analyze(address);
295
it = findDisassemblyEntry(entries,address,false);
296
}
297
298
if (it != entries.end()) {
299
DisassemblyEntry *entry = it->second;
300
if (entry->disassemble(address, dest, insertSymbols, cpuDebug))
301
return;
302
}
303
304
dest.type = DISTYPE_OTHER;
305
memset(&dest.info, 0, sizeof(dest.info));
306
dest.info.opcodeAddress = address;
307
if (address % 4)
308
dest.totalSize = ((address+3) & ~3)-address;
309
else
310
dest.totalSize = 4;
311
if (Memory::IsValidRange(address, 4)) {
312
dest.name = "ERROR";
313
dest.params = "Disassembly failure";
314
} else {
315
dest.name = "-";
316
dest.params.clear();
317
}
318
}
319
320
u32 DisassemblyManager::getStartAddress(u32 address)
321
{
322
std::lock_guard<std::recursive_mutex> guard(entriesLock_);
323
auto it = findDisassemblyEntry(entries,address,false);
324
if (it == entries.end())
325
{
326
analyze(address);
327
it = findDisassemblyEntry(entries,address,false);
328
if (it == entries.end())
329
return address;
330
}
331
332
DisassemblyEntry* entry = it->second;
333
int line = entry->getLineNum(address,true);
334
return entry->getLineAddress(line);
335
}
336
337
u32 DisassemblyManager::getNthPreviousAddress(u32 address, int n)
338
{
339
std::lock_guard<std::recursive_mutex> guard(entriesLock_);
340
while (Memory::IsValidAddress(address))
341
{
342
auto it = findDisassemblyEntry(entries,address,false);
343
if (it == entries.end())
344
break;
345
while (it != entries.end()) {
346
DisassemblyEntry* entry = it->second;
347
int oldLineNum = entry->getLineNum(address,true);
348
if (n <= oldLineNum)
349
{
350
return entry->getLineAddress(oldLineNum-n);
351
}
352
353
address = entry->getLineAddress(0)-1;
354
n -= oldLineNum+1;
355
it = findDisassemblyEntry(entries,address,false);
356
}
357
358
analyze(address-127,128);
359
}
360
361
return (address - n * 4) & ~3;
362
}
363
364
u32 DisassemblyManager::getNthNextAddress(u32 address, int n)
365
{
366
std::lock_guard<std::recursive_mutex> guard(entriesLock_);
367
while (Memory::IsValidAddress(address))
368
{
369
auto it = findDisassemblyEntry(entries,address,false);
370
if (it == entries.end()) {
371
break;
372
}
373
374
while (it != entries.end())
375
{
376
DisassemblyEntry* entry = it->second;
377
int oldLineNum = entry->getLineNum(address,true);
378
int oldNumLines = entry->getNumLines();
379
if (oldLineNum+n < oldNumLines)
380
{
381
return entry->getLineAddress(oldLineNum+n);
382
}
383
384
address = entry->getLineAddress(0)+entry->getTotalSize();
385
n -= (oldNumLines-oldLineNum);
386
it = findDisassemblyEntry(entries,address,false);
387
}
388
389
analyze(address);
390
}
391
392
return (address + n * 4) & ~3;
393
}
394
395
DisassemblyManager::~DisassemblyManager() {
396
}
397
398
void DisassemblyManager::clear()
399
{
400
std::lock_guard<std::recursive_mutex> guard(entriesLock_);
401
for (auto it = entries.begin(); it != entries.end(); it++)
402
{
403
delete it->second;
404
}
405
entries.clear();
406
}
407
408
DisassemblyFunction::DisassemblyFunction(u32 _address, u32 _size): address(_address), size(_size)
409
{
410
if (PSP_GetBootState() != BootState::Complete)
411
return;
412
413
hash = computeHash(address,size);
414
load();
415
}
416
417
DisassemblyFunction::~DisassemblyFunction() {
418
clear();
419
}
420
421
void DisassemblyFunction::recheck()
422
{
423
if (PSP_GetBootState() != BootState::Complete)
424
return;
425
426
HashType newHash = computeHash(address,size);
427
if (hash != newHash)
428
{
429
hash = newHash;
430
clear();
431
load();
432
}
433
}
434
435
int DisassemblyFunction::getNumLines()
436
{
437
std::lock_guard<std::recursive_mutex> guard(lock_);
438
return (int) lineAddresses.size();
439
}
440
441
int DisassemblyFunction::getLineNum(u32 address, bool findStart)
442
{
443
std::lock_guard<std::recursive_mutex> guard(lock_);
444
if (findStart)
445
{
446
int last = (int)lineAddresses.size() - 1;
447
for (int i = 0; i < last; i++)
448
{
449
u32 next = lineAddresses[i + 1];
450
if (lineAddresses[i] <= address && next > address)
451
return i;
452
}
453
if (lineAddresses[last] <= address && this->address + this->size > address)
454
return last;
455
}
456
else
457
{
458
int last = (int)lineAddresses.size() - 1;
459
for (int i = 0; i < last; i++)
460
{
461
if (lineAddresses[i] == address)
462
return i;
463
}
464
if (lineAddresses[last] == address)
465
return last;
466
}
467
468
return 0;
469
}
470
471
u32 DisassemblyFunction::getLineAddress(int line)
472
{
473
std::lock_guard<std::recursive_mutex> guard(lock_);
474
return lineAddresses[line];
475
}
476
477
bool DisassemblyFunction::disassemble(u32 address, DisassemblyLineInfo &dest, bool insertSymbols, DebugInterface *cpuDebug)
478
{
479
std::lock_guard<std::recursive_mutex> guard(lock_);
480
auto it = findDisassemblyEntry(entries,address,false);
481
if (it == entries.end())
482
return false;
483
484
return it->second->disassemble(address, dest, insertSymbols, cpuDebug);
485
}
486
487
void DisassemblyFunction::getBranchLines(u32 start, u32 size, std::vector<BranchLine>& dest)
488
{
489
u32 end = start+size;
490
491
std::lock_guard<std::recursive_mutex> guard(lock_);
492
for (size_t i = 0; i < lines.size(); i++)
493
{
494
BranchLine& line = lines[i];
495
496
u32 first = line.first;
497
u32 second = line.second;
498
499
// skip branches that are entirely before or entirely after the window
500
if ((first < start && second < start) ||
501
(first > end && second > end))
502
continue;
503
504
dest.push_back(line);
505
}
506
}
507
508
#define NUM_LANES 16
509
510
void DisassemblyFunction::generateBranchLines()
511
{
512
struct LaneInfo
513
{
514
bool used;
515
u32 end;
516
};
517
518
LaneInfo lanes[NUM_LANES];
519
for (int i = 0; i < NUM_LANES; i++)
520
lanes[i].used = false;
521
522
u32 end = address+size;
523
524
std::lock_guard<std::recursive_mutex> guard(lock_);
525
DebugInterface *cpu = g_disassemblyManager.getCpu();
526
for (u32 funcPos = address; funcPos < end; funcPos += 4)
527
{
528
MIPSAnalyst::MipsOpcodeInfo opInfo = MIPSAnalyst::GetOpcodeInfo(cpu, funcPos);
529
530
bool inFunction = (opInfo.branchTarget >= address && opInfo.branchTarget < end);
531
if (opInfo.isBranch && !opInfo.isBranchToRegister && !opInfo.isLinkedBranch && inFunction) {
532
if (!Memory::IsValidAddress(opInfo.branchTarget))
533
continue;
534
535
BranchLine line;
536
if (opInfo.branchTarget < funcPos) {
537
line.first = opInfo.branchTarget;
538
line.second = funcPos;
539
line.type = LINE_UP;
540
} else {
541
line.first = funcPos;
542
line.second = opInfo.branchTarget;
543
line.type = LINE_DOWN;
544
}
545
546
lines.push_back(line);
547
}
548
}
549
550
std::sort(lines.begin(),lines.end());
551
for (size_t i = 0; i < lines.size(); i++)
552
{
553
for (int l = 0; l < NUM_LANES; l++)
554
{
555
if (lines[i].first > lanes[l].end)
556
lanes[l].used = false;
557
}
558
559
int lane = -1;
560
for (int l = 0; l < NUM_LANES; l++)
561
{
562
if (lanes[l].used == false)
563
{
564
lane = l;
565
break;
566
}
567
}
568
569
if (lane == -1)
570
{
571
// Let's just pile on.
572
lines[i].laneIndex = 15;
573
continue;
574
}
575
576
lanes[lane].end = lines[i].second;
577
lanes[lane].used = true;
578
lines[i].laneIndex = lane;
579
}
580
}
581
582
void DisassemblyFunction::addOpcodeSequence(u32 start, u32 end)
583
{
584
DisassemblyOpcode* opcode = new DisassemblyOpcode(start,(end-start)/4);
585
std::lock_guard<std::recursive_mutex> guard(lock_);
586
entries[start] = opcode;
587
lineAddresses.reserve((end - start) / 4);
588
for (u32 pos = start; pos < end; pos += 4)
589
{
590
lineAddresses.push_back(pos);
591
}
592
}
593
594
void DisassemblyFunction::load()
595
{
596
generateBranchLines();
597
598
// gather all branch targets
599
std::set<u32> branchTargets;
600
{
601
std::lock_guard<std::recursive_mutex> guard(lock_);
602
for (size_t i = 0; i < lines.size(); i++)
603
{
604
switch (lines[i].type)
605
{
606
case LINE_DOWN:
607
branchTargets.insert(lines[i].second);
608
break;
609
case LINE_UP:
610
branchTargets.insert(lines[i].first);
611
break;
612
default:
613
break;
614
}
615
}
616
}
617
618
DebugInterface *cpu = g_disassemblyManager.getCpu();
619
u32 funcPos = address;
620
u32 funcEnd = address+size;
621
622
u32 nextData = g_symbolMap->GetNextSymbolAddress(funcPos-1,ST_DATA);
623
u32 opcodeSequenceStart = funcPos;
624
while (funcPos < funcEnd)
625
{
626
if (funcPos == nextData)
627
{
628
if (opcodeSequenceStart != funcPos)
629
addOpcodeSequence(opcodeSequenceStart,funcPos);
630
631
DisassemblyData* data = new DisassemblyData(funcPos,g_symbolMap->GetDataSize(funcPos),g_symbolMap->GetDataType(funcPos));
632
std::lock_guard<std::recursive_mutex> guard(lock_);
633
entries[funcPos] = data;
634
lineAddresses.push_back(funcPos);
635
funcPos += data->getTotalSize();
636
637
nextData = g_symbolMap->GetNextSymbolAddress(funcPos-1,ST_DATA);
638
opcodeSequenceStart = funcPos;
639
continue;
640
}
641
642
// force align
643
if (funcPos % 4)
644
{
645
u32 nextPos = (funcPos+3) & ~3;
646
647
DisassemblyComment* comment = new DisassemblyComment(funcPos,nextPos-funcPos,".align","4");
648
std::lock_guard<std::recursive_mutex> guard(lock_);
649
entries[funcPos] = comment;
650
lineAddresses.push_back(funcPos);
651
652
funcPos = nextPos;
653
opcodeSequenceStart = funcPos;
654
continue;
655
}
656
657
MIPSAnalyst::MipsOpcodeInfo opInfo = MIPSAnalyst::GetOpcodeInfo(cpu,funcPos);
658
u32 opAddress = funcPos;
659
funcPos += 4;
660
661
// skip branches and their delay slots
662
if (opInfo.isBranch)
663
{
664
funcPos += 4;
665
continue;
666
}
667
668
// lui
669
if (MIPS_GET_OP(opInfo.encodedOpcode) == 0x0F && funcPos < funcEnd && funcPos != nextData)
670
{
671
MIPSOpcode next = Memory::Read_Instruction(funcPos);
672
MIPSInfo nextInfo = MIPSGetInfo(next);
673
674
u32 immediate = ((opInfo.encodedOpcode & 0xFFFF) << 16) + (s16)(next.encoding & 0xFFFF);
675
int rt = MIPS_GET_RT(opInfo.encodedOpcode);
676
677
int nextRs = MIPS_GET_RS(next.encoding);
678
int nextRt = MIPS_GET_RT(next.encoding);
679
680
// both rs and rt of the second op have to match rt of the first,
681
// otherwise there may be hidden consequences if the macro is displayed.
682
// also, don't create a macro if something branches into the middle of it
683
if (nextRs == rt && nextRt == rt && branchTargets.find(funcPos) == branchTargets.end())
684
{
685
DisassemblyMacro* macro = NULL;
686
switch (MIPS_GET_OP(next.encoding))
687
{
688
case 0x09: // addiu
689
macro = new DisassemblyMacro(opAddress);
690
macro->setMacroLi(immediate,rt);
691
funcPos += 4;
692
break;
693
case 0x20: // lb
694
case 0x21: // lh
695
case 0x23: // lw
696
case 0x24: // lbu
697
case 0x25: // lhu
698
case 0x28: // sb
699
case 0x29: // sh
700
case 0x2B: // sw
701
macro = new DisassemblyMacro(opAddress);
702
703
int dataSize = MIPSGetMemoryAccessSize(next);
704
if (dataSize == 0) {
705
delete macro;
706
return;
707
}
708
709
macro->setMacroMemory(MIPSGetName(next),immediate,rt,dataSize);
710
funcPos += 4;
711
break;
712
}
713
714
if (macro != NULL)
715
{
716
if (opcodeSequenceStart != opAddress)
717
addOpcodeSequence(opcodeSequenceStart,opAddress);
718
719
std::lock_guard<std::recursive_mutex> guard(lock_);
720
entries[opAddress] = macro;
721
for (int i = 0; i < macro->getNumLines(); i++)
722
{
723
lineAddresses.push_back(macro->getLineAddress(i));
724
}
725
726
opcodeSequenceStart = funcPos;
727
continue;
728
}
729
}
730
}
731
732
// just a normal opcode
733
}
734
735
if (opcodeSequenceStart != funcPos)
736
addOpcodeSequence(opcodeSequenceStart,funcPos);
737
}
738
739
void DisassemblyFunction::clear()
740
{
741
std::lock_guard<std::recursive_mutex> guard(lock_);
742
for (auto it = entries.begin(); it != entries.end(); it++)
743
{
744
delete it->second;
745
}
746
747
entries.clear();
748
lines.clear();
749
lineAddresses.clear();
750
hash = 0;
751
}
752
753
bool DisassemblyOpcode::disassemble(u32 address, DisassemblyLineInfo &dest, bool insertSymbols, DebugInterface *cpuDebug) {
754
char opcode[64],arguments[256];
755
char dizz[512];
756
DisAsm(address, dizz, sizeof(dizz));
757
parseDisasm(dizz, opcode, sizeof(opcode), arguments, sizeof(arguments), insertSymbols);
758
dest.type = DISTYPE_OPCODE;
759
dest.name = opcode;
760
dest.params = arguments;
761
dest.totalSize = 4;
762
dest.info = MIPSAnalyst::GetOpcodeInfo(cpuDebug, address);
763
return true;
764
}
765
766
void DisassemblyOpcode::getBranchLines(u32 start, u32 size, std::vector<BranchLine>& dest)
767
{
768
if (start < address)
769
{
770
size = start+size-address;
771
start = address;
772
}
773
774
if (start+size > address+num*4)
775
size = address+num*4-start;
776
777
int lane = 0;
778
for (u32 pos = start; pos < start+size; pos += 4)
779
{
780
MIPSAnalyst::MipsOpcodeInfo info = MIPSAnalyst::GetOpcodeInfo(g_disassemblyManager.getCpu(),pos);
781
if (info.isBranch && !info.isBranchToRegister && !info.isLinkedBranch) {
782
if (!Memory::IsValidAddress(info.branchTarget))
783
continue;
784
785
BranchLine line;
786
line.laneIndex = lane++;
787
788
if (info.branchTarget < pos) {
789
line.first = info.branchTarget;
790
line.second = pos;
791
line.type = LINE_UP;
792
} else {
793
line.first = pos;
794
line.second = info.branchTarget;
795
line.type = LINE_DOWN;
796
}
797
798
dest.push_back(line);
799
}
800
}
801
}
802
803
804
void DisassemblyMacro::setMacroLi(u32 _immediate, u8 _rt)
805
{
806
type = MACRO_LI;
807
name = "li";
808
immediate = _immediate;
809
rt = _rt;
810
numOpcodes = 2;
811
}
812
813
void DisassemblyMacro::setMacroMemory(std::string_view _name, u32 _immediate, u8 _rt, int _dataSize)
814
{
815
type = MACRO_MEMORYIMM;
816
name = _name;
817
immediate = _immediate;
818
rt = _rt;
819
dataSize = _dataSize;
820
numOpcodes = 2;
821
}
822
823
bool DisassemblyMacro::disassemble(u32 address, DisassemblyLineInfo &dest, bool insertSymbols, DebugInterface *cpuDebug)
824
{
825
char buffer[64];
826
dest.type = DISTYPE_MACRO;
827
dest.info = MIPSAnalyst::GetOpcodeInfo(cpuDebug, address);
828
829
std::string addressSymbol;
830
switch (type)
831
{
832
case MACRO_LI:
833
dest.name = name;
834
835
addressSymbol = g_symbolMap->GetLabelString(immediate);
836
if (!addressSymbol.empty() && insertSymbols) {
837
snprintf(buffer, sizeof(buffer), "%s,%s", MIPSDebugInterface::GetRegName(0, rt).c_str(), addressSymbol.c_str());
838
} else {
839
snprintf(buffer, sizeof(buffer), "%s,0x%08X", MIPSDebugInterface::GetRegName(0, rt).c_str(), immediate);
840
}
841
842
dest.params = buffer;
843
844
dest.info.hasRelevantAddress = true;
845
dest.info.relevantAddress = immediate;
846
break;
847
case MACRO_MEMORYIMM:
848
dest.name = name;
849
850
addressSymbol = g_symbolMap->GetLabelString(immediate);
851
if (!addressSymbol.empty() && insertSymbols) {
852
snprintf(buffer, sizeof(buffer), "%s,%s", MIPSDebugInterface::GetRegName(0, rt).c_str(), addressSymbol.c_str());
853
} else {
854
snprintf(buffer, sizeof(buffer), "%s,0x%08X", MIPSDebugInterface::GetRegName(0, rt).c_str(), immediate);
855
}
856
857
dest.params = buffer;
858
859
dest.info.isDataAccess = true;
860
dest.info.dataAddress = immediate;
861
dest.info.dataSize = dataSize;
862
863
dest.info.hasRelevantAddress = true;
864
dest.info.relevantAddress = immediate;
865
break;
866
default:
867
return false;
868
}
869
870
dest.totalSize = getTotalSize();
871
return true;
872
}
873
874
DisassemblyData::DisassemblyData(u32 _address, u32 _size, DataType _type): address(_address), size(_size), type(_type)
875
{
876
_dbg_assert_(PSP_GetBootState() == BootState::Complete);
877
hash = computeHash(address,size);
878
createLines();
879
}
880
881
void DisassemblyData::recheck()
882
{
883
if (PSP_GetBootState() != BootState::Complete)
884
return;
885
886
HashType newHash = computeHash(address,size);
887
if (newHash != hash)
888
{
889
hash = newHash;
890
createLines();
891
}
892
}
893
894
bool DisassemblyData::disassemble(u32 address, DisassemblyLineInfo &dest, bool insertSymbols, DebugInterface *cpuDebug)
895
{
896
dest.type = DISTYPE_DATA;
897
898
switch (type)
899
{
900
case DATATYPE_BYTE:
901
dest.name = ".byte";
902
break;
903
case DATATYPE_HALFWORD:
904
dest.name = ".half";
905
break;
906
case DATATYPE_WORD:
907
dest.name = ".word";
908
break;
909
case DATATYPE_ASCII:
910
dest.name = ".ascii";
911
break;
912
default:
913
return false;
914
}
915
916
std::lock_guard<std::recursive_mutex> guard(lock_);
917
auto it = lines.find(address);
918
if (it == lines.end())
919
return false;
920
921
dest.params = it->second.text;
922
dest.totalSize = it->second.size;
923
return true;
924
}
925
926
int DisassemblyData::getLineNum(u32 address, bool findStart)
927
{
928
std::lock_guard<std::recursive_mutex> guard(lock_);
929
auto it = lines.upper_bound(address);
930
if (it != lines.end())
931
{
932
if (it == lines.begin())
933
return 0;
934
it--;
935
return it->second.lineNum;
936
}
937
938
return lines.rbegin()->second.lineNum;
939
}
940
941
void DisassemblyData::createLines()
942
{
943
std::lock_guard<std::recursive_mutex> guard(lock_);
944
lines.clear();
945
lineAddresses.clear();
946
947
u32 pos = address;
948
const u32 end = address+size;
949
const u32 maxChars = g_disassemblyManager.getMaxParamChars();
950
951
std::string currentLine;
952
u32 currentLineStart = pos;
953
954
int lineCount = 0;
955
if (type == DATATYPE_ASCII)
956
{
957
bool inString = false;
958
while (pos < end)
959
{
960
u8 b = Memory::Read_U8(pos++);
961
if (b >= 0x20 && b <= 0x7F)
962
{
963
if (currentLine.size()+1 >= maxChars)
964
{
965
if (inString == true)
966
currentLine += "\"";
967
968
DataEntry entry = {currentLine,pos-1-currentLineStart,lineCount++};
969
lines[currentLineStart] = entry;
970
lineAddresses.push_back(currentLineStart);
971
972
currentLine.clear();
973
currentLineStart = pos-1;
974
inString = false;
975
}
976
977
if (inString == false)
978
currentLine += "\"";
979
currentLine += (char)b;
980
inString = true;
981
} else {
982
char buffer[64];
983
if (pos == end && b == 0)
984
truncate_cpy(buffer, "0");
985
else
986
snprintf(buffer, sizeof(buffer), "0x%02X", b);
987
988
if (currentLine.size()+strlen(buffer) >= maxChars)
989
{
990
if (inString == true)
991
currentLine += "\"";
992
993
DataEntry entry = {currentLine,pos-1-currentLineStart,lineCount++};
994
lines[currentLineStart] = entry;
995
lineAddresses.push_back(currentLineStart);
996
997
currentLine.clear();
998
currentLineStart = pos-1;
999
inString = false;
1000
}
1001
1002
bool comma = false;
1003
if (currentLine.size() != 0)
1004
comma = true;
1005
1006
if (inString)
1007
currentLine += "\"";
1008
1009
if (comma)
1010
currentLine += ",";
1011
1012
currentLine += buffer;
1013
inString = false;
1014
}
1015
}
1016
1017
if (inString == true)
1018
currentLine += "\"";
1019
1020
if (currentLine.size() != 0)
1021
{
1022
DataEntry entry = {currentLine,pos-currentLineStart,lineCount++};
1023
lines[currentLineStart] = entry;
1024
lineAddresses.push_back(currentLineStart);
1025
}
1026
} else {
1027
while (pos < end)
1028
{
1029
char buffer[256];
1030
u32 value;
1031
1032
u32 currentPos = pos;
1033
1034
switch (type)
1035
{
1036
case DATATYPE_BYTE:
1037
value = Memory::Read_U8(pos);
1038
snprintf(buffer, sizeof(buffer), "0x%02X", value);
1039
pos++;
1040
break;
1041
case DATATYPE_HALFWORD:
1042
value = Memory::Read_U16(pos);
1043
snprintf(buffer, sizeof(buffer), "0x%04X", value);
1044
pos += 2;
1045
break;
1046
case DATATYPE_WORD:
1047
{
1048
value = Memory::Read_U32(pos);
1049
const std::string label = g_symbolMap->GetLabelString(value);
1050
if (!label.empty())
1051
snprintf(buffer, sizeof(buffer), "%s", label.c_str());
1052
else
1053
snprintf(buffer, sizeof(buffer), "0x%08X", value);
1054
pos += 4;
1055
}
1056
break;
1057
default:
1058
break;
1059
}
1060
1061
size_t len = strlen(buffer);
1062
if (currentLine.size() != 0 && currentLine.size()+len >= maxChars)
1063
{
1064
DataEntry entry = {currentLine,currentPos-currentLineStart,lineCount++};
1065
lines[currentLineStart] = entry;
1066
lineAddresses.push_back(currentLineStart);
1067
1068
currentLine.clear();
1069
currentLineStart = currentPos;
1070
}
1071
1072
if (currentLine.size() != 0)
1073
currentLine += ",";
1074
currentLine += buffer;
1075
}
1076
1077
if (currentLine.size() != 0) {
1078
DataEntry entry = {currentLine,pos-currentLineStart,lineCount++};
1079
lines[currentLineStart] = entry;
1080
lineAddresses.push_back(currentLineStart);
1081
}
1082
}
1083
}
1084
1085
1086
DisassemblyComment::DisassemblyComment(u32 _address, u32 _size, std::string_view _name, std::string_view _param)
1087
: address(_address), size(_size), name(_name), param(_param) {}
1088
1089
bool DisassemblyComment::disassemble(u32 address, DisassemblyLineInfo &dest, bool insertSymbols, DebugInterface *cpuDebug) {
1090
dest.type = DISTYPE_OTHER;
1091
dest.name = name;
1092
dest.params = param;
1093
dest.totalSize = size;
1094
return true;
1095
}
1096
1097
bool GetDisasmAddressText(u32 address, char *dest, size_t bufSize, bool abbreviateLabels, bool showData, bool displaySymbols) {
1098
if (!Memory::IsValid4AlignedAddress(address)) {
1099
snprintf(dest, bufSize, "(bad address!)");
1100
return true;
1101
}
1102
if (displaySymbols) {
1103
const std::string addressSymbol = g_symbolMap->GetLabelString(address);
1104
if (!addressSymbol.empty()) {
1105
for (int k = 0; addressSymbol[k] != 0; k++) {
1106
// abbreviate long names
1107
if (abbreviateLabels && k == 16 && addressSymbol[k+1] != 0) {
1108
*dest++ = '+';
1109
break;
1110
}
1111
*dest++ = addressSymbol[k];
1112
}
1113
*dest++ = ':';
1114
*dest = 0;
1115
return true;
1116
} else {
1117
snprintf(dest, bufSize, " %08X",address);
1118
return false;
1119
}
1120
} else {
1121
if (showData) {
1122
const u32 encoding = Memory::Read_Instruction(address, true).encoding;
1123
snprintf(dest, bufSize, "%08X %08X", address, encoding);
1124
} else {
1125
snprintf(dest, bufSize, "%08X", address);
1126
}
1127
return false;
1128
}
1129
}
1130
1131
// Utilify function from the old debugger.
1132
std::string DisassembleRange(u32 start, u32 size, bool displaySymbols, MIPSDebugInterface *debugger) {
1133
auto memLock = Memory::Lock();
1134
std::string result;
1135
1136
// gather all branch targets without labels
1137
std::set<u32> branchAddresses;
1138
for (u32 i = 0; i < size; i += debugger->getInstructionSize(0)) {
1139
MIPSAnalyst::MipsOpcodeInfo info = MIPSAnalyst::GetOpcodeInfo(debugger, start + i);
1140
1141
if (info.isBranch && g_symbolMap->GetLabelString(info.branchTarget).empty()) {
1142
if (branchAddresses.find(info.branchTarget) == branchAddresses.end()) {
1143
branchAddresses.insert(info.branchTarget);
1144
}
1145
}
1146
}
1147
1148
u32 disAddress = start;
1149
bool previousLabel = true;
1150
DisassemblyLineInfo line;
1151
while (disAddress < start + size) {
1152
char addressText[64], buffer[512];
1153
1154
g_disassemblyManager.getLine(disAddress, displaySymbols, line, debugger);
1155
bool isLabel = GetDisasmAddressText(disAddress, addressText, sizeof(addressText), false, line.type == DISTYPE_OPCODE, displaySymbols);
1156
1157
if (isLabel) {
1158
if (!previousLabel)
1159
result += "\r\n";
1160
snprintf(buffer, sizeof(buffer), "%s\r\n\r\n", addressText);
1161
result += buffer;
1162
} else if (branchAddresses.find(disAddress) != branchAddresses.end()) {
1163
if (!previousLabel)
1164
result += "\r\n";
1165
snprintf(buffer, sizeof(buffer), "pos_%08X:\r\n\r\n", disAddress);
1166
result += buffer;
1167
}
1168
1169
if (line.info.isBranch && !line.info.isBranchToRegister
1170
&& g_symbolMap->GetLabelString(line.info.branchTarget).empty()
1171
&& branchAddresses.find(line.info.branchTarget) != branchAddresses.end()) {
1172
snprintf(buffer, sizeof(buffer), "pos_%08X", line.info.branchTarget);
1173
line.params = line.params.substr(0, line.params.find("0x")) + buffer;
1174
}
1175
1176
snprintf(buffer, sizeof(buffer), "\t%s\t%s\r\n", line.name.c_str(), line.params.c_str());
1177
result += buffer;
1178
previousLabel = isLabel;
1179
disAddress += line.totalSize;
1180
}
1181
1182
return result;
1183
}
1184
1185