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