From 561379f5c25550d34a95ffec5ef65c62443b7762 Mon Sep 17 00:00:00 2001 From: Kingcom Date: Thu, 28 Nov 2013 00:33:21 +0100 Subject: [PATCH] Create data directives in disassembler --- Core/Debugger/DisassemblyManager.cpp | 301 +++++++++++++++++++++++++-- Core/Debugger/DisassemblyManager.h | 53 ++++- Core/Debugger/SymbolMap.cpp | 5 +- Core/Debugger/SymbolMap.h | 2 +- Windows/Debugger/CtrlDisAsmView.cpp | 97 ++++++--- Windows/Debugger/CtrlDisAsmView.h | 2 +- 6 files changed, 410 insertions(+), 50 deletions(-) diff --git a/Core/Debugger/DisassemblyManager.cpp b/Core/Debugger/DisassemblyManager.cpp index 7229219d50..47a4a21216 100644 --- a/Core/Debugger/DisassemblyManager.cpp +++ b/Core/Debugger/DisassemblyManager.cpp @@ -27,6 +27,7 @@ std::map DisassemblyManager::entries; DebugInterface* DisassemblyManager::cpu; +int DisassemblyManager::maxParamChars = 29; bool isInInterval(u32 start, u32 size, u32 value) { @@ -139,19 +140,56 @@ void DisassemblyManager::analyze(u32 address, u32 size = 1024) } SymbolInfo info; - if (symbolMap.GetSymbolInfo(&info,address) && info.type == ST_FUNCTION) + if (!symbolMap.GetSymbolInfo(&info,address,ST_ALL)) { - DisassemblyFunction* function = new DisassemblyFunction(info.address,info.size); - entries[info.address] = function; - address = info.address+info.size; - } else { - u32 next = symbolMap.GetNextSymbolAddress(address+1,ST_FUNCTION); + if (address % 4) + { + u32 next = std::min((address+3) & ~3,symbolMap.GetNextSymbolAddress(address,ST_ALL)); + DisassemblyData* data = new DisassemblyData(address,next-address,DATATYPE_BYTE); + entries[address] = data; + address = next; + continue; + } + + u32 next = symbolMap.GetNextSymbolAddress(address,ST_ALL); + + if (next % 4) + { + u32 alignedNext = next & ~3; + + if (alignedNext != address) + { + DisassemblyOpcode* opcode = new DisassemblyOpcode(address,(alignedNext-address)/4); + entries[address] = opcode; + } + + DisassemblyData* data = new DisassemblyData(address,next-alignedNext,DATATYPE_BYTE); + entries[alignedNext] = data; + } else { + DisassemblyOpcode* opcode = new DisassemblyOpcode(address,(next-address)/4); + entries[address] = opcode; + } - // let's just assume anything otuside a function is a normal opcode - DisassemblyOpcode* opcode = new DisassemblyOpcode(address,(next-address)/4); - entries[address] = opcode; - address = next; + continue; + } + + switch (info.type) + { + case ST_FUNCTION: + { + DisassemblyFunction* function = new DisassemblyFunction(info.address,info.size); + entries[info.address] = function; + address = info.address+info.size; + } + break; + case ST_DATA: + { + DisassemblyData* data = new DisassemblyData(info.address,info.size,symbolMap.GetDataType(info.address)); + entries[info.address] = data; + address = info.address+info.size; + } + break; } } @@ -244,7 +282,7 @@ u32 DisassemblyManager::getNthPreviousAddress(u32 address, int n) return address-n*4; } - +// 0x09509780 u32 DisassemblyManager::getNthNextAddress(u32 address, int n) { while (Memory::IsValidAddress(address)) @@ -449,9 +487,39 @@ void DisassemblyFunction::load() u32 funcPos = address; u32 funcEnd = address+size; + u32 nextData = symbolMap.GetNextSymbolAddress(funcPos-1,ST_DATA); u32 opcodeSequenceStart = funcPos; while (funcPos < funcEnd) { + if (funcPos == nextData) + { + if (opcodeSequenceStart != funcPos) + addOpcodeSequence(opcodeSequenceStart,funcPos); + + DisassemblyData* data = new DisassemblyData(funcPos,symbolMap.GetDataSize(funcPos),symbolMap.GetDataType(funcPos)); + entries[funcPos] = data; + lineAddresses.push_back(funcPos); + funcPos += data->getTotalSize(); + + nextData = symbolMap.GetNextSymbolAddress(funcPos-1,ST_DATA); + opcodeSequenceStart = funcPos; + continue; + } + + // force align + if (funcPos % 4) + { + u32 nextPos = (funcPos+3) & ~3; + + DisassemblyComment* comment = new DisassemblyComment(funcPos,nextPos-funcPos,".align","4"); + entries[funcPos] = comment; + lineAddresses.push_back(funcPos); + + funcPos = nextPos; + opcodeSequenceStart = funcPos; + continue; + } + MIPSAnalyst::MipsOpcodeInfo opInfo = MIPSAnalyst::GetOpcodeInfo(cpu,funcPos); u32 opAddress = funcPos; funcPos += 4; @@ -464,7 +532,7 @@ void DisassemblyFunction::load() } // lui - if (MIPS_GET_OP(opInfo.encodedOpcode) == 0x0F && funcPos < funcEnd) + if (MIPS_GET_OP(opInfo.encodedOpcode) == 0x0F && funcPos < funcEnd && funcPos != nextData) { MIPSOpcode next = Memory::Read_Instruction(funcPos); MIPSInfo nextInfo = MIPSGetInfo(next); @@ -562,6 +630,7 @@ bool DisassemblyOpcode::disassemble(u32 address, DisassemblyLineInfo& dest, bool char opcode[64],arguments[256]; const char *dizz = DisassemblyManager::getCpu()->disasm(address,4); parseDisasm(dizz,opcode,arguments,insertSymbols); + dest.type = DISTYPE_OPCODE; dest.name = opcode; dest.params = arguments; dest.totalSize = 4; @@ -570,6 +639,12 @@ bool DisassemblyOpcode::disassemble(u32 address, DisassemblyLineInfo& dest, bool void DisassemblyOpcode::getBranchLines(u32 start, u32 size, std::vector& dest) { + if (start < address) + start = address; + + if (start+size > address+num*4) + size = address+num*4-start; + int lane = 0; for (u32 pos = start; pos < start+size; pos += 4) { @@ -618,6 +693,7 @@ void DisassemblyMacro::setMacroMemory(std::string _name, u32 _immediate, u8 _rt, bool DisassemblyMacro::disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols) { char buffer[64]; + dest.type = DISTYPE_OTHER; const char* addressSymbol; switch (type) @@ -665,3 +741,204 @@ bool DisassemblyMacro::disassemble(u32 address, DisassemblyLineInfo& dest, bool dest.totalSize = getTotalSize(); return true; } + + +bool DisassemblyData::disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols) +{ + dest.type = DISTYPE_DATA; + + switch (type) + { + case DATATYPE_BYTE: + dest.name = ".byte"; + break; + case DATATYPE_HALFWORD: + dest.name = ".half"; + break; + case DATATYPE_WORD: + dest.name = ".word"; + break; + case DATATYPE_ASCII: + dest.name = ".ascii"; + break; + default: + return false; + } + + auto it = lines.find(address); + dest.params = it->second.text; + dest.totalSize = it->second.size; + return true; +} + +int DisassemblyData::getLineNum(u32 address, bool findStart) +{ + auto it = lines.upper_bound(address); + if (it != lines.end()) + { + if (it == lines.begin()) + return 0; + it--; + return it->second.lineNum; + } + + return lines.rbegin()->second.lineNum; +} + +void DisassemblyData::createLines() +{ + lines.clear(); + lineAddresses.clear(); + + u32 pos = address; + u32 end = address+size; + u32 maxChars = DisassemblyManager::getMaxParamChars(); + + std::string currentLine; + u32 currentLineStart = pos; + + int lineCount = 0; + if (type == DATATYPE_ASCII) + { + bool inString = false; + while (pos < end) + { + u8 b = Memory::Read_U8(pos++); + if (b >= 0x20 && b <= 0x7F) + { + if (currentLine.size()+1 >= maxChars) + { + if (inString == true) + currentLine += "\""; + + DataEntry entry = {currentLine,pos-1-currentLineStart,lineCount++}; + lines[currentLineStart] = entry; + lineAddresses.push_back(currentLineStart); + + currentLine = ""; + currentLineStart = pos-1; + inString = false; + } + + if (inString == false) + currentLine += "\""; + currentLine += (char)b; + inString = true; + } else { + char buffer[64]; + if (pos == end && b == 0) + strcpy(buffer,"0"); + else + sprintf(buffer,"0x%02X",b); + + if (currentLine.size()+strlen(buffer) >= maxChars) + { + if (inString == true) + currentLine += "\""; + + DataEntry entry = {currentLine,pos-1-currentLineStart,lineCount++}; + lines[currentLineStart] = entry; + lineAddresses.push_back(currentLineStart); + + currentLine = ""; + currentLineStart = pos-1; + inString = false; + } + + bool comma = false; + if (currentLine.size() != 0) + comma = true; + + if (inString) + currentLine += "\""; + + if (comma) + currentLine += ","; + + currentLine += buffer; + inString = false; + } + } + + if (inString == true) + currentLine += "\""; + + if (currentLine.size() != 0) + { + DataEntry entry = {currentLine,pos-currentLineStart,lineCount++}; + lines[currentLineStart] = entry; + lineAddresses.push_back(currentLineStart); + } + } else { + while (pos < end) + { + char buffer[64]; + u32 value; + + u32 currentPos = pos; + + switch (type) + { + case DATATYPE_BYTE: + value = Memory::Read_U8(pos); + sprintf(buffer,"0x%02X",value); + pos++; + break; + case DATATYPE_HALFWORD: + value = Memory::Read_U16(pos); + sprintf(buffer,"0x%04X",value); + pos += 2; + break; + case DATATYPE_WORD: + { + value = Memory::Read_U32(pos); + const char* label = symbolMap.GetLabelName(value); + if (label != NULL) + sprintf(buffer,"%s",label); + else + sprintf(buffer,"0x%08X",value); + pos += 4; + } + break; + } + + int len = strlen(buffer); + if (currentLine.size() != 0 && currentLine.size()+len >= maxChars) + { + DataEntry entry = {currentLine,currentPos-currentLineStart,lineCount++}; + lines[currentLineStart] = entry; + lineAddresses.push_back(currentLineStart); + + currentLine = ""; + currentLineStart = currentPos; + } + + if (currentLine.size() != 0) + currentLine += ","; + currentLine += buffer; + } + + if (currentLine.size() != 0) + { + DataEntry entry = {currentLine,pos-currentLineStart,lineCount++}; + lines[currentLineStart] = entry; + lineAddresses.push_back(currentLineStart); + } + } +} + + +DisassemblyComment::DisassemblyComment(u32 _address, u32 _size, std::string _name, std::string _param) + : address(_address), size(_size), name(_name), param(_param) +{ + +} + +bool DisassemblyComment::disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols) +{ + dest.type = DISTYPE_OTHER; + dest.name = name; + dest.params = param; + dest.totalSize = size; + return true; +} \ No newline at end of file diff --git a/Core/Debugger/DisassemblyManager.h b/Core/Debugger/DisassemblyManager.h index 52126ccb19..84ee49acc7 100644 --- a/Core/Debugger/DisassemblyManager.h +++ b/Core/Debugger/DisassemblyManager.h @@ -19,7 +19,7 @@ #include "Globals.h" #include "Core/MIPS/MIPSAnalyst.h" -enum DisassemblyLineType { DISTYPE_OPCODE, DISTYPE_DATA }; +enum DisassemblyLineType { DISTYPE_OPCODE, DISTYPE_DATA, DISTYPE_OTHER }; struct DisassemblyLineInfo { @@ -130,6 +130,54 @@ private: }; +class DisassemblyData: public DisassemblyEntry +{ +public: + DisassemblyData(u32 _address, u32 _size, DataType _type): address(_address), size(_size), type(_type) { createLines(); }; + virtual ~DisassemblyData() { }; + + virtual void recheck() { createLines(); }; + virtual int getNumLines() { return (int)lines.size(); }; + virtual int getLineNum(u32 address, bool findStart); + virtual u32 getLineAddress(int line) { return lineAddresses[line]; }; + virtual u32 getTotalSize() { return size; }; + virtual bool disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols); +private: + void createLines(); + + struct DataEntry + { + std::string text; + u32 size; + int lineNum; + }; + + u32 address; + u32 size; + DataType type; + std::map lines; + std::vector lineAddresses; +}; + +class DisassemblyComment: public DisassemblyEntry +{ +public: + DisassemblyComment(u32 _address, u32 _size, std::string name, std::string param); + virtual ~DisassemblyComment() { }; + + virtual void recheck() { }; + virtual int getNumLines() { return 1; }; + virtual int getLineNum(u32 address, bool findStart) { return 0; }; + virtual u32 getLineAddress(int line) { return address; }; + virtual u32 getTotalSize() { return size; }; + virtual bool disassemble(u32 address, DisassemblyLineInfo& dest, bool insertSymbols); +private: + u32 address; + u32 size; + std::string name; + std::string param; +}; + class DebugInterface; class DisassemblyManager @@ -138,6 +186,7 @@ public: void clear(); void setCpu(DebugInterface* _cpu) { cpu = _cpu; }; + void setMaxParamChars(int num) { maxParamChars = num; clear(); }; void getLine(u32 address, bool insertSymbols, DisassemblyLineInfo& dest); void analyze(u32 address, u32 size); std::vector getBranchLines(u32 start, u32 size); @@ -147,10 +196,12 @@ public: u32 getNthNextAddress(u32 address, int n = 1); static DebugInterface* getCpu() { return cpu; }; + static int getMaxParamChars() { return maxParamChars; }; private: DisassemblyEntry* getEntry(u32 address); static std::map entries; static DebugInterface* cpu; + static int maxParamChars; }; bool isInInterval(u32 start, u32 size, u32 value); \ No newline at end of file diff --git a/Core/Debugger/SymbolMap.cpp b/Core/Debugger/SymbolMap.cpp index 0b4ff43f1b..cc4f37fd6b 100644 --- a/Core/Debugger/SymbolMap.cpp +++ b/Core/Debugger/SymbolMap.cpp @@ -186,6 +186,9 @@ bool SymbolMap::LoadNocashSym(const char *filename) } else if (strcasecmp(value,".dbl") == 0) { AddData(address,size,DATATYPE_WORD); + } else if (strcasecmp(value,".asc") == 0) + { + AddData(address,size,DATATYPE_ASCII); } } } else { // labels @@ -254,7 +257,7 @@ bool SymbolMap::GetSymbolInfo(SymbolInfo *info, u32 address, SymbolType symmask) { info->type = ST_DATA; info->address = dataAddress; - info->size = GetDataSize(functionAddress); + info->size = GetDataSize(dataAddress); } return true; diff --git a/Core/Debugger/SymbolMap.h b/Core/Debugger/SymbolMap.h index d086183df4..d81ea20f1d 100644 --- a/Core/Debugger/SymbolMap.h +++ b/Core/Debugger/SymbolMap.h @@ -43,7 +43,7 @@ struct SymbolEntry u32 size; }; -enum DataType { DATATYPE_NONE, DATATYPE_BYTE, DATATYPE_HALFWORD, DATATYPE_WORD }; +enum DataType { DATATYPE_NONE, DATATYPE_BYTE, DATATYPE_HALFWORD, DATATYPE_WORD, DATATYPE_ASCII }; #ifdef _WIN32 struct HWND__; diff --git a/Windows/Debugger/CtrlDisAsmView.cpp b/Windows/Debugger/CtrlDisAsmView.cpp index e893fafc8c..3b1b655c94 100644 --- a/Windows/Debugger/CtrlDisAsmView.cpp +++ b/Windows/Debugger/CtrlDisAsmView.cpp @@ -201,7 +201,7 @@ COLORREF scaleColor(COLORREF color, float factor) return (color & 0xFF000000) | (b << 16) | (g << 8) | r; } -bool CtrlDisAsmView::getDisasmAddressText(u32 address, char* dest, bool abbreviateLabels) +bool CtrlDisAsmView::getDisasmAddressText(u32 address, char* dest, bool abbreviateLabels, bool showData) { if (displaySymbols) { @@ -226,7 +226,10 @@ bool CtrlDisAsmView::getDisasmAddressText(u32 address, char* dest, bool abbrevia return false; } } else { - sprintf(dest,"%08X %08X",address,Memory::Read_U32(address)); + if (showData) + sprintf(dest,"%08X %08X",address,Memory::Read_U32(address)); + else + sprintf(dest,"%08X",address); return false; } } @@ -482,7 +485,7 @@ void CtrlDisAsmView::onPaint(WPARAM wParam, LPARAM lParam) SetTextColor(hdc,textColor); char addressText[64]; - getDisasmAddressText(address,addressText,true); + getDisasmAddressText(address,addressText,true,line.type == DISTYPE_OPCODE); TextOutA(hdc,pixelPositions.addressStart,rowY1+2,addressText,(int)strlen(addressText)); if (isInInterval(address,line.totalSize,debugger->getPC())) @@ -933,6 +936,7 @@ void CtrlDisAsmView::onMouseUp(WPARAM wParam, LPARAM lParam, int button) symbolMap.RemoveFunction(funcBegin,true); symbolMap.SortSymbols(); + manager.clear(); SendMessage(GetParent(wnd), WM_DEB_MAPLOADED, 0, 0); } @@ -966,6 +970,7 @@ void CtrlDisAsmView::onMouseUp(WPARAM wParam, LPARAM lParam, int button) snprintf(symname,128,"u_un_%08X",curAddress); symbolMap.AddFunction(symname,curAddress,newSize); symbolMap.SortSymbols(); + manager.clear(); SendMessage(GetParent(wnd), WM_DEB_MAPLOADED, 0, 0); } @@ -1007,48 +1012,72 @@ void CtrlDisAsmView::updateStatusBarText() manager.getLine(curAddress,true,line); text[0] = 0; - if (line.info.isDataAccess) + if (line.type == DISTYPE_OPCODE) { - if (!Memory::IsValidAddress(line.info.dataAddress)) + if (line.info.isDataAccess) { - sprintf(text,"Invalid address %08X",line.info.dataAddress); - } else { - switch (line.info.dataSize) + if (!Memory::IsValidAddress(line.info.dataAddress)) { - case 1: - sprintf(text,"[%08X] = %02X",line.info.dataAddress,Memory::Read_U8(line.info.dataAddress)); - break; - case 2: - sprintf(text,"[%08X] = %04X",line.info.dataAddress,Memory::Read_U16(line.info.dataAddress)); - break; - case 4: - // TODO: Could also be a float... + sprintf(text,"Invalid address %08X",line.info.dataAddress); + } else { + switch (line.info.dataSize) { - u32 data = Memory::Read_U32(line.info.dataAddress); - const char* addressSymbol = symbolMap.GetLabelName(data); - if (addressSymbol) + case 1: + sprintf(text,"[%08X] = %02X",line.info.dataAddress,Memory::Read_U8(line.info.dataAddress)); + break; + case 2: + sprintf(text,"[%08X] = %04X",line.info.dataAddress,Memory::Read_U16(line.info.dataAddress)); + break; + case 4: + // TODO: Could also be a float... { - sprintf(text,"[%08X] = %s (%08X)",line.info.dataAddress,addressSymbol,data); - } else { - sprintf(text,"[%08X] = %08X",line.info.dataAddress,data); + u32 data = Memory::Read_U32(line.info.dataAddress); + const char* addressSymbol = symbolMap.GetLabelName(data); + if (addressSymbol) + { + sprintf(text,"[%08X] = %s (%08X)",line.info.dataAddress,addressSymbol,data); + } else { + sprintf(text,"[%08X] = %08X",line.info.dataAddress,data); + } + break; } + case 16: + // TODO: vector break; } - case 16: - // TODO: vector - break; } } - } - if (line.info.isBranch) - { - const char* addressSymbol = symbolMap.GetLabelName(line.info.branchTarget); - if (addressSymbol == NULL) + if (line.info.isBranch) { - sprintf(text,"%08X",line.info.branchTarget); + const char* addressSymbol = symbolMap.GetLabelName(line.info.branchTarget); + if (addressSymbol == NULL) + { + sprintf(text,"%08X",line.info.branchTarget); + } else { + sprintf(text,"%08X = %s",line.info.branchTarget,addressSymbol); + } + } + } else if (line.type == DISTYPE_DATA) + { + u32 start = symbolMap.GetDataStart(curAddress); + if (start == -1) + start = curAddress; + + u32 diff = curAddress-start; + const char* label = symbolMap.GetLabelName(start); + + if (label != NULL) + { + if (diff != 0) + sprintf(text,"%08X (%s) + %08X",start,label,diff); + else + sprintf(text,"%08X (%s)",start,label); } else { - sprintf(text,"%08X = %s",line.info.branchTarget,addressSymbol); + if (diff != 0) + sprintf(text,"%08X + %08X",start,diff); + else + sprintf(text,"%08X",start); } } @@ -1109,7 +1138,7 @@ void CtrlDisAsmView::search(bool continueSearch) manager.getLine(searchAddress,displaySymbols,lineInfo); char addressText[64]; - getDisasmAddressText(searchAddress,addressText,true); + getDisasmAddressText(searchAddress,addressText,true,lineInfo.type == DISTYPE_OPCODE); const char* opcode = lineInfo.name.c_str(); const char* arguments = lineInfo.params.c_str(); @@ -1176,7 +1205,7 @@ std::string CtrlDisAsmView::disassembleRange(u32 start, u32 size) char addressText[64],buffer[512]; manager.getLine(disAddress,displaySymbols,line); - bool isLabel = getDisasmAddressText(disAddress,addressText,false); + bool isLabel = getDisasmAddressText(disAddress,addressText,false,line.type == DISTYPE_OPCODE); if (isLabel) { diff --git a/Windows/Debugger/CtrlDisAsmView.h b/Windows/Debugger/CtrlDisAsmView.h index ff4ebd2fa3..36936d3def 100644 --- a/Windows/Debugger/CtrlDisAsmView.h +++ b/Windows/Debugger/CtrlDisAsmView.h @@ -74,7 +74,7 @@ class CtrlDisAsmView void search(bool continueSearch); void followBranch(); void calculatePixelPositions(); - bool getDisasmAddressText(u32 address, char* dest, bool abbreviateLabels); + bool getDisasmAddressText(u32 address, char* dest, bool abbreviateLabels, bool showData); void updateStatusBarText(); void drawBranchLine(HDC hdc, std::map& addressPositions, BranchLine& line); void copyInstructions(u32 startAddr, u32 endAddr, bool withDisasm);