CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

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

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