Merge pull request #90 from gizmo98/patch-2
[libretro-ppsspp.git] / Core / Debugger / DisassemblyManager.cpp
blobb35f7ca8a9133e436a2306d7780e78956dc8694a
1 // Copyright (c) 2012- PPSSPP Project.
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.
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.
12 // A copy of the GPL 2.0 should have been included with the program.
13 // If not, see http://www.gnu.org/licenses/
15 // Official git repository and contact information can be found at
16 // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
18 #include <string>
19 #include <algorithm>
20 #include <map>
22 #include "ext/xxhash.h"
24 #include "Common/CommonTypes.h"
25 #include "Core/MemMap.h"
26 #include "Core/System.h"
27 #include "Core/MIPS/MIPSCodeUtils.h"
28 #include "Core/MIPS/MIPSTables.h"
29 #include "Core/Debugger/DebugInterface.h"
30 #include "Core/Debugger/SymbolMap.h"
31 #include "Core/Debugger/DisassemblyManager.h"
33 std::map<u32, DisassemblyEntry*> DisassemblyManager::entries;
34 DebugInterface* DisassemblyManager::cpu;
35 int DisassemblyManager::maxParamChars = 29;
37 bool isInInterval(u32 start, u32 size, u32 value)
39 return start <= value && value <= (start+size-1);
43 static u32 computeHash(u32 address, u32 size)
45 #ifdef _M_X64
46 return XXH64(Memory::GetPointer(address), size, 0xBACD7814BACD7814LL);
47 #else
48 return XXH32(Memory::GetPointer(address), size, 0xBACD7814);
49 #endif
53 void parseDisasm(const char* disasm, char* opcode, char* arguments, bool insertSymbols)
55 // copy opcode
56 while (*disasm != 0 && *disasm != '\t')
58 *opcode++ = *disasm++;
60 *opcode = 0;
62 if (*disasm++ == 0)
64 *arguments = 0;
65 return;
68 const char* jumpAddress = strstr(disasm,"->$");
69 const char* jumpRegister = strstr(disasm,"->");
70 while (*disasm != 0)
72 // parse symbol
73 if (disasm == jumpAddress)
75 u32 branchTarget;
76 sscanf(disasm+3,"%08x",&branchTarget);
78 const std::string addressSymbol = symbolMap.GetLabelString(branchTarget);
79 if (!addressSymbol.empty() && insertSymbols)
81 arguments += sprintf(arguments,"%s",addressSymbol.c_str());
82 } else {
83 arguments += sprintf(arguments,"0x%08X",branchTarget);
86 disasm += 3+8;
87 continue;
90 if (disasm == jumpRegister)
91 disasm += 2;
93 if (*disasm == ' ')
95 disasm++;
96 continue;
98 *arguments++ = *disasm++;
101 *arguments = 0;
104 std::map<u32,DisassemblyEntry*>::iterator findDisassemblyEntry(std::map<u32,DisassemblyEntry*>& entries, u32 address, bool exact)
106 if (exact)
107 return entries.find(address);
109 if (entries.size() == 0)
110 return entries.end();
112 // find first elem that's >= address
113 auto it = entries.lower_bound(address);
114 if (it != entries.end())
116 // it may be an exact match
117 if (isInInterval(it->second->getLineAddress(0),it->second->getTotalSize(),address))
118 return it;
120 // otherwise it may point to the next
121 if (it != entries.begin())
123 it--;
124 if (isInInterval(it->second->getLineAddress(0),it->second->getTotalSize(),address))
125 return it;
129 // check last entry manually
130 auto rit = entries.rbegin();
131 if (isInInterval(rit->second->getLineAddress(0),rit->second->getTotalSize(),address))
133 return (++rit).base();
136 // no match otherwise
137 return entries.end();
140 void DisassemblyManager::analyze(u32 address, u32 size = 1024)
142 u32 end = address+size;
144 address &= ~3;
145 u32 start = address;
147 while (address < end && start <= address)
149 if (!PSP_IsInited())
150 return;
152 auto it = findDisassemblyEntry(entries,address,false);
153 if (it != entries.end())
155 DisassemblyEntry* entry = it->second;
156 entry->recheck();
157 address = entry->getLineAddress(0)+entry->getTotalSize();
158 continue;
161 SymbolInfo info;
162 if (!symbolMap.GetSymbolInfo(&info,address,ST_ALL))
164 if (address % 4)
166 u32 next = std::min<u32>((address+3) & ~3,symbolMap.GetNextSymbolAddress(address,ST_ALL));
167 DisassemblyData* data = new DisassemblyData(address,next-address,DATATYPE_BYTE);
168 entries[address] = data;
169 address = next;
170 continue;
173 u32 next = symbolMap.GetNextSymbolAddress(address,ST_ALL);
175 if ((next % 4) && next != (u32)-1)
177 u32 alignedNext = next & ~3;
179 if (alignedNext != address)
181 DisassemblyOpcode* opcode = new DisassemblyOpcode(address,(alignedNext-address)/4);
182 entries[address] = opcode;
185 DisassemblyData* data = new DisassemblyData(address,next-alignedNext,DATATYPE_BYTE);
186 entries[alignedNext] = data;
187 } else {
188 DisassemblyOpcode* opcode = new DisassemblyOpcode(address,(next-address)/4);
189 entries[address] = opcode;
192 address = next;
193 continue;
196 switch (info.type)
198 case ST_FUNCTION:
200 DisassemblyFunction* function = new DisassemblyFunction(info.address,info.size);
201 entries[info.address] = function;
202 address = info.address+info.size;
204 break;
205 case ST_DATA:
207 DisassemblyData* data = new DisassemblyData(info.address,info.size,symbolMap.GetDataType(info.address));
208 entries[info.address] = data;
209 address = info.address+info.size;
211 break;
212 default:
213 break;
219 std::vector<BranchLine> DisassemblyManager::getBranchLines(u32 start, u32 size)
221 std::vector<BranchLine> result;
223 auto it = findDisassemblyEntry(entries,start,false);
224 if (it != entries.end())
228 it->second->getBranchLines(start,size,result);
229 it++;
230 } while (it != entries.end() && start+size > it->second->getLineAddress(0));
233 return result;
236 void DisassemblyManager::getLine(u32 address, bool insertSymbols, DisassemblyLineInfo& dest)
238 auto it = findDisassemblyEntry(entries,address,false);
239 if (it == entries.end())
241 analyze(address);
242 it = findDisassemblyEntry(entries,address,false);
244 if (it == entries.end())
246 if (address % 4)
247 dest.totalSize = ((address+3) & ~3)-address;
248 else
249 dest.totalSize = 4;
250 dest.name = "ERROR";
251 dest.params = "Disassembly failure";
252 return;
256 DisassemblyEntry* entry = it->second;
257 if (entry->disassemble(address,dest,insertSymbols))
258 return;
260 if (address % 4)
261 dest.totalSize = ((address+3) & ~3)-address;
262 else
263 dest.totalSize = 4;
264 dest.name = "ERROR";
265 dest.params = "Disassembly failure";
268 u32 DisassemblyManager::getStartAddress(u32 address)
270 auto it = findDisassemblyEntry(entries,address,false);
271 if (it == entries.end())
273 analyze(address);
274 it = findDisassemblyEntry(entries,address,false);
275 if (it == entries.end())
276 return address;
279 DisassemblyEntry* entry = it->second;
280 int line = entry->getLineNum(address,true);
281 return entry->getLineAddress(line);
284 u32 DisassemblyManager::getNthPreviousAddress(u32 address, int n)
286 while (Memory::IsValidAddress(address))
288 auto it = findDisassemblyEntry(entries,address,false);
290 while (it != entries.end())
292 DisassemblyEntry* entry = it->second;
293 int oldLineNum = entry->getLineNum(address,true);
294 int oldNumLines = entry->getNumLines();
295 if (n <= oldLineNum)
297 return entry->getLineAddress(oldLineNum-n);
300 address = entry->getLineAddress(0)-1;
301 n -= oldLineNum+1;
302 it = findDisassemblyEntry(entries,address,false);
305 analyze(address-127,128);
308 return address-n*4;
311 u32 DisassemblyManager::getNthNextAddress(u32 address, int n)
313 while (Memory::IsValidAddress(address))
315 auto it = findDisassemblyEntry(entries,address,false);
317 while (it != entries.end())
319 DisassemblyEntry* entry = it->second;
320 int oldLineNum = entry->getLineNum(address,true);
321 int oldNumLines = entry->getNumLines();
322 if (oldLineNum+n < oldNumLines)
324 return entry->getLineAddress(oldLineNum+n);
327 address = entry->getLineAddress(0)+entry->getTotalSize();
328 n -= (oldNumLines-oldLineNum);
329 it = findDisassemblyEntry(entries,address,false);
332 analyze(address);
335 return address+n*4;
338 void DisassemblyManager::clear()
340 for (auto it = entries.begin(); it != entries.end(); it++)
342 delete it->second;
344 entries.clear();
347 DisassemblyFunction::DisassemblyFunction(u32 _address, u32 _size): address(_address), size(_size)
349 auto memLock = Memory::Lock();
350 if (!PSP_IsInited())
351 return;
353 hash = computeHash(address,size);
354 load();
357 void DisassemblyFunction::recheck()
359 auto memLock = Memory::Lock();
360 if (!PSP_IsInited())
361 return;
363 HashType newHash = computeHash(address,size);
364 if (hash != newHash)
366 hash = newHash;
367 clear();
368 load();
372 int DisassemblyFunction::getNumLines()
374 return (int) lineAddresses.size();
377 int DisassemblyFunction::getLineNum(u32 address, bool findStart)
379 if (findStart)
381 int last = (int)lineAddresses.size() - 1;
382 for (int i = 0; i < last; i++)
384 u32 next = lineAddresses[i + 1];
385 if (lineAddresses[i] <= address && next > address)
386 return i;
388 if (lineAddresses[last] <= address && this->address + this->size > address)
389 return last;
391 else
393 int last = (int)lineAddresses.size() - 1;
394 for (int i = 0; i < last; i++)
396 u32 next = lineAddresses[i + 1];
397 if (lineAddresses[i] == address)
398 return i;
400 if (lineAddresses[last] == address)
401 return last;
404 return 0;
407 u32 DisassemblyFunction::getLineAddress(int line)
409 return lineAddresses[line];
412 bool DisassemblyFunction::disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols)
414 auto it = findDisassemblyEntry(entries,address,false);
415 if (it == entries.end())
416 return false;
418 return it->second->disassemble(address,dest,insertSymbols);
421 void DisassemblyFunction::getBranchLines(u32 start, u32 size, std::vector<BranchLine>& dest)
423 u32 end = start+size;
425 for (size_t i = 0; i < lines.size(); i++)
427 BranchLine& line = lines[i];
429 u32 first = line.first;
430 u32 second = line.second;
432 // skip branches that are entirely before or entirely after the window
433 if ((first < start && second < start) ||
434 (first > end && second > end))
435 continue;
437 dest.push_back(line);
441 #define NUM_LANES 16
443 void DisassemblyFunction::generateBranchLines()
445 struct LaneInfo
447 bool used;
448 u32 end;
451 LaneInfo lanes[NUM_LANES];
452 for (int i = 0; i < NUM_LANES; i++)
453 lanes[i].used = false;
455 u32 end = address+size;
457 DebugInterface* cpu = DisassemblyManager::getCpu();
458 for (u32 funcPos = address; funcPos < end; funcPos += 4)
460 MIPSAnalyst::MipsOpcodeInfo opInfo = MIPSAnalyst::GetOpcodeInfo(cpu,funcPos);
462 bool inFunction = (opInfo.branchTarget >= address && opInfo.branchTarget < end);
463 if (opInfo.isBranch && !opInfo.isBranchToRegister && !opInfo.isLinkedBranch && inFunction)
465 BranchLine line;
466 if (opInfo.branchTarget < funcPos)
468 line.first = opInfo.branchTarget;
469 line.second = funcPos;
470 line.type = LINE_UP;
471 } else {
472 line.first = funcPos;
473 line.second = opInfo.branchTarget;
474 line.type = LINE_DOWN;
477 lines.push_back(line);
481 std::sort(lines.begin(),lines.end());
482 for (size_t i = 0; i < lines.size(); i++)
484 for (int l = 0; l < NUM_LANES; l++)
486 if (lines[i].first > lanes[l].end)
487 lanes[l].used = false;
490 int lane = -1;
491 for (int l = 0; l < NUM_LANES; l++)
493 if (lanes[l].used == false)
495 lane = l;
496 break;
500 if (lane == -1)
502 // error
503 continue;
506 lanes[lane].end = lines[i].second;
507 lanes[lane].used = true;
508 lines[i].laneIndex = lane;
512 void DisassemblyFunction::addOpcodeSequence(u32 start, u32 end)
514 DisassemblyOpcode* opcode = new DisassemblyOpcode(start,(end-start)/4);
515 entries[start] = opcode;
516 for (u32 pos = start; pos < end; pos += 4)
518 lineAddresses.push_back(pos);
522 void DisassemblyFunction::load()
524 generateBranchLines();
526 // gather all branch targets
527 std::set<u32> branchTargets;
528 for (size_t i = 0; i < lines.size(); i++)
530 switch (lines[i].type)
532 case LINE_DOWN:
533 branchTargets.insert(lines[i].second);
534 break;
535 case LINE_UP:
536 branchTargets.insert(lines[i].first);
537 break;
538 default:
539 break;
543 DebugInterface* cpu = DisassemblyManager::getCpu();
544 u32 funcPos = address;
545 u32 funcEnd = address+size;
547 u32 nextData = symbolMap.GetNextSymbolAddress(funcPos-1,ST_DATA);
548 u32 opcodeSequenceStart = funcPos;
549 while (funcPos < funcEnd)
551 if (funcPos == nextData)
553 if (opcodeSequenceStart != funcPos)
554 addOpcodeSequence(opcodeSequenceStart,funcPos);
556 DisassemblyData* data = new DisassemblyData(funcPos,symbolMap.GetDataSize(funcPos),symbolMap.GetDataType(funcPos));
557 entries[funcPos] = data;
558 lineAddresses.push_back(funcPos);
559 funcPos += data->getTotalSize();
561 nextData = symbolMap.GetNextSymbolAddress(funcPos-1,ST_DATA);
562 opcodeSequenceStart = funcPos;
563 continue;
566 // force align
567 if (funcPos % 4)
569 u32 nextPos = (funcPos+3) & ~3;
571 DisassemblyComment* comment = new DisassemblyComment(funcPos,nextPos-funcPos,".align","4");
572 entries[funcPos] = comment;
573 lineAddresses.push_back(funcPos);
575 funcPos = nextPos;
576 opcodeSequenceStart = funcPos;
577 continue;
580 MIPSAnalyst::MipsOpcodeInfo opInfo = MIPSAnalyst::GetOpcodeInfo(cpu,funcPos);
581 u32 opAddress = funcPos;
582 funcPos += 4;
584 // skip branches and their delay slots
585 if (opInfo.isBranch)
587 funcPos += 4;
588 continue;
591 // lui
592 if (MIPS_GET_OP(opInfo.encodedOpcode) == 0x0F && funcPos < funcEnd && funcPos != nextData)
594 MIPSOpcode next = Memory::Read_Instruction(funcPos);
595 MIPSInfo nextInfo = MIPSGetInfo(next);
597 u32 immediate = ((opInfo.encodedOpcode & 0xFFFF) << 16) + (s16)(next.encoding & 0xFFFF);
598 int rt = MIPS_GET_RT(opInfo.encodedOpcode);
600 int nextRs = MIPS_GET_RS(next.encoding);
601 int nextRt = MIPS_GET_RT(next.encoding);
603 // both rs and rt of the second op have to match rt of the first,
604 // otherwise there may be hidden consequences if the macro is displayed.
605 // also, don't create a macro if something branches into the middle of it
606 if (nextRs == rt && nextRt == rt && branchTargets.find(funcPos) == branchTargets.end())
608 DisassemblyMacro* macro = NULL;
609 switch (MIPS_GET_OP(next.encoding))
611 case 0x09: // addiu
612 macro = new DisassemblyMacro(opAddress);
613 macro->setMacroLi(immediate,rt);
614 funcPos += 4;
615 break;
616 case 0x20: // lb
617 case 0x21: // lh
618 case 0x23: // lw
619 case 0x24: // lbu
620 case 0x25: // lhu
621 case 0x28: // sb
622 case 0x29: // sh
623 case 0x2B: // sw
624 macro = new DisassemblyMacro(opAddress);
626 int dataSize;
627 switch (nextInfo & MEMTYPE_MASK) {
628 case MEMTYPE_BYTE:
629 dataSize = 1;
630 break;
631 case MEMTYPE_HWORD:
632 dataSize = 2;
633 break;
634 case MEMTYPE_WORD:
635 case MEMTYPE_FLOAT:
636 dataSize = 4;
637 break;
638 case MEMTYPE_VQUAD:
639 dataSize = 16;
640 break;
641 default:
642 delete macro;
643 return;
646 macro->setMacroMemory(MIPSGetName(next),immediate,rt,dataSize);
647 funcPos += 4;
648 break;
651 if (macro != NULL)
653 if (opcodeSequenceStart != opAddress)
654 addOpcodeSequence(opcodeSequenceStart,opAddress);
656 entries[opAddress] = macro;
657 for (int i = 0; i < macro->getNumLines(); i++)
659 lineAddresses.push_back(macro->getLineAddress(i));
662 opcodeSequenceStart = funcPos;
663 continue;
668 // just a normal opcode
671 if (opcodeSequenceStart != funcPos)
672 addOpcodeSequence(opcodeSequenceStart,funcPos);
675 void DisassemblyFunction::clear()
677 for (auto it = entries.begin(); it != entries.end(); it++)
679 delete it->second;
682 entries.clear();
683 lines.clear();
684 lineAddresses.clear();
685 hash = 0;
688 bool DisassemblyOpcode::disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols)
690 char opcode[64],arguments[256];
691 const char *dizz = DisassemblyManager::getCpu()->disasm(address,4);
692 parseDisasm(dizz,opcode,arguments,insertSymbols);
693 dest.type = DISTYPE_OPCODE;
694 dest.name = opcode;
695 dest.params = arguments;
696 dest.totalSize = 4;
697 dest.info = MIPSAnalyst::GetOpcodeInfo(DisassemblyManager::getCpu(),address);
698 return true;
701 void DisassemblyOpcode::getBranchLines(u32 start, u32 size, std::vector<BranchLine>& dest)
703 if (start < address)
705 size = start+size-address;
706 start = address;
709 if (start+size > address+num*4)
710 size = address+num*4-start;
712 int lane = 0;
713 for (u32 pos = start; pos < start+size; pos += 4)
715 MIPSAnalyst::MipsOpcodeInfo info = MIPSAnalyst::GetOpcodeInfo(DisassemblyManager::getCpu(),pos);
716 if (info.isBranch && !info.isBranchToRegister && !info.isLinkedBranch)
718 BranchLine line;
719 line.laneIndex = lane++;
721 if (info.branchTarget < pos)
723 line.first = info.branchTarget;
724 line.second = pos;
725 line.type = LINE_UP;
726 } else {
727 line.first = pos;
728 line.second = info.branchTarget;
729 line.type = LINE_DOWN;
732 dest.push_back(line);
738 void DisassemblyMacro::setMacroLi(u32 _immediate, u8 _rt)
740 type = MACRO_LI;
741 name = "li";
742 immediate = _immediate;
743 rt = _rt;
744 numOpcodes = 2;
747 void DisassemblyMacro::setMacroMemory(std::string _name, u32 _immediate, u8 _rt, int _dataSize)
749 type = MACRO_MEMORYIMM;
750 name = _name;
751 immediate = _immediate;
752 rt = _rt;
753 dataSize = _dataSize;
754 numOpcodes = 2;
757 bool DisassemblyMacro::disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols)
759 char buffer[64];
760 dest.type = DISTYPE_MACRO;
761 dest.info = MIPSAnalyst::GetOpcodeInfo(DisassemblyManager::getCpu(),address);
763 std::string addressSymbol;
764 switch (type)
766 case MACRO_LI:
767 dest.name = name;
769 addressSymbol = symbolMap.GetLabelString(immediate);
770 if (!addressSymbol.empty() && insertSymbols)
772 sprintf(buffer,"%s,%s",DisassemblyManager::getCpu()->GetRegName(0,rt),addressSymbol.c_str());
773 } else {
774 sprintf(buffer,"%s,0x%08X",DisassemblyManager::getCpu()->GetRegName(0,rt),immediate);
777 dest.params = buffer;
779 dest.info.hasRelevantAddress = true;
780 dest.info.relevantAddress = immediate;
781 break;
782 case MACRO_MEMORYIMM:
783 dest.name = name;
785 addressSymbol = symbolMap.GetLabelString(immediate);
786 if (!addressSymbol.empty() && insertSymbols)
788 sprintf(buffer,"%s,%s",DisassemblyManager::getCpu()->GetRegName(0,rt),addressSymbol.c_str());
789 } else {
790 sprintf(buffer,"%s,0x%08X",DisassemblyManager::getCpu()->GetRegName(0,rt),immediate);
793 dest.params = buffer;
795 dest.info.isDataAccess = true;
796 dest.info.dataAddress = immediate;
797 dest.info.dataSize = dataSize;
799 dest.info.hasRelevantAddress = true;
800 dest.info.relevantAddress = immediate;
801 break;
802 default:
803 return false;
806 dest.totalSize = getTotalSize();
807 return true;
811 DisassemblyData::DisassemblyData(u32 _address, u32 _size, DataType _type): address(_address), size(_size), type(_type)
813 auto memLock = Memory::Lock();
814 if (!PSP_IsInited())
815 return;
817 hash = computeHash(address,size);
818 createLines();
821 void DisassemblyData::recheck()
823 auto memLock = Memory::Lock();
824 if (!PSP_IsInited())
825 return;
827 HashType newHash = computeHash(address,size);
828 if (newHash != hash)
830 hash = newHash;
831 createLines();
835 bool DisassemblyData::disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols)
837 dest.type = DISTYPE_DATA;
839 switch (type)
841 case DATATYPE_BYTE:
842 dest.name = ".byte";
843 break;
844 case DATATYPE_HALFWORD:
845 dest.name = ".half";
846 break;
847 case DATATYPE_WORD:
848 dest.name = ".word";
849 break;
850 case DATATYPE_ASCII:
851 dest.name = ".ascii";
852 break;
853 default:
854 return false;
857 auto it = lines.find(address);
858 if (it == lines.end())
859 return false;
861 dest.params = it->second.text;
862 dest.totalSize = it->second.size;
863 return true;
866 int DisassemblyData::getLineNum(u32 address, bool findStart)
868 auto it = lines.upper_bound(address);
869 if (it != lines.end())
871 if (it == lines.begin())
872 return 0;
873 it--;
874 return it->second.lineNum;
877 return lines.rbegin()->second.lineNum;
880 void DisassemblyData::createLines()
882 lines.clear();
883 lineAddresses.clear();
885 u32 pos = address;
886 u32 end = address+size;
887 u32 maxChars = DisassemblyManager::getMaxParamChars();
889 std::string currentLine;
890 u32 currentLineStart = pos;
892 int lineCount = 0;
893 if (type == DATATYPE_ASCII)
895 bool inString = false;
896 while (pos < end)
898 u8 b = Memory::Read_U8(pos++);
899 if (b >= 0x20 && b <= 0x7F)
901 if (currentLine.size()+1 >= maxChars)
903 if (inString == true)
904 currentLine += "\"";
906 DataEntry entry = {currentLine,pos-1-currentLineStart,lineCount++};
907 lines[currentLineStart] = entry;
908 lineAddresses.push_back(currentLineStart);
910 currentLine = "";
911 currentLineStart = pos-1;
912 inString = false;
915 if (inString == false)
916 currentLine += "\"";
917 currentLine += (char)b;
918 inString = true;
919 } else {
920 char buffer[64];
921 if (pos == end && b == 0)
922 strcpy(buffer,"0");
923 else
924 sprintf(buffer,"0x%02X",b);
926 if (currentLine.size()+strlen(buffer) >= maxChars)
928 if (inString == true)
929 currentLine += "\"";
931 DataEntry entry = {currentLine,pos-1-currentLineStart,lineCount++};
932 lines[currentLineStart] = entry;
933 lineAddresses.push_back(currentLineStart);
935 currentLine = "";
936 currentLineStart = pos-1;
937 inString = false;
940 bool comma = false;
941 if (currentLine.size() != 0)
942 comma = true;
944 if (inString)
945 currentLine += "\"";
947 if (comma)
948 currentLine += ",";
950 currentLine += buffer;
951 inString = false;
955 if (inString == true)
956 currentLine += "\"";
958 if (currentLine.size() != 0)
960 DataEntry entry = {currentLine,pos-currentLineStart,lineCount++};
961 lines[currentLineStart] = entry;
962 lineAddresses.push_back(currentLineStart);
964 } else {
965 while (pos < end)
967 char buffer[256];
968 u32 value;
970 u32 currentPos = pos;
972 switch (type)
974 case DATATYPE_BYTE:
975 value = Memory::Read_U8(pos);
976 snprintf(buffer, sizeof(buffer), "0x%02X", value);
977 pos++;
978 break;
979 case DATATYPE_HALFWORD:
980 value = Memory::Read_U16(pos);
981 snprintf(buffer, sizeof(buffer), "0x%04X", value);
982 pos += 2;
983 break;
984 case DATATYPE_WORD:
986 value = Memory::Read_U32(pos);
987 const std::string label = symbolMap.GetLabelString(value);
988 if (!label.empty())
989 snprintf(buffer, sizeof(buffer), "%s", label.c_str());
990 else
991 snprintf(buffer, sizeof(buffer), "0x%08X", value);
992 pos += 4;
994 break;
995 default:
996 break;
999 size_t len = strlen(buffer);
1000 if (currentLine.size() != 0 && currentLine.size()+len >= maxChars)
1002 DataEntry entry = {currentLine,currentPos-currentLineStart,lineCount++};
1003 lines[currentLineStart] = entry;
1004 lineAddresses.push_back(currentLineStart);
1006 currentLine = "";
1007 currentLineStart = currentPos;
1010 if (currentLine.size() != 0)
1011 currentLine += ",";
1012 currentLine += buffer;
1015 if (currentLine.size() != 0) {
1016 DataEntry entry = {currentLine,pos-currentLineStart,lineCount++};
1017 lines[currentLineStart] = entry;
1018 lineAddresses.push_back(currentLineStart);
1024 DisassemblyComment::DisassemblyComment(u32 _address, u32 _size, std::string _name, std::string _param)
1025 : address(_address), size(_size), name(_name), param(_param)
1030 bool DisassemblyComment::disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols)
1032 dest.type = DISTYPE_OTHER;
1033 dest.name = name;
1034 dest.params = param;
1035 dest.totalSize = size;
1036 return true;