1 // copyright (c) 2020-2021 hors<horsicq@gmail.com>
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a copy
4 // of this software and associated documentation files (the "Software"), to deal
5 // in the Software without restriction, including without limitation the rights
6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 // copies of the Software, and to permit persons to whom the Software is
8 // furnished to do so, subject to the following conditions:
9
10 // The above copyright notice and this permission notice shall be included in all
11 // copies or substantial portions of the Software.
12
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 // SOFTWARE.
20 //
21 #include "xdisasmview.h"
22 #include "xdisasmview.h"
23
XDisasmView(QWidget * pParent)24 XDisasmView::XDisasmView(QWidget *pParent) : XDeviceTableView(pParent)
25 {
26 g_handle=0;
27
28 g_nBytesProLine=1;
29
30 g_scGoToAddress=nullptr;
31 g_scGoToOffset=nullptr;
32 g_scGoToEntryPoint=nullptr;
33 g_scDumpToFile=nullptr;
34 g_scSelectAll=nullptr;
35 g_scCopyAsHex=nullptr;
36 g_scCopyCursorOffset=nullptr;
37 g_scCopyCursorAddress=nullptr;
38 g_scFind=nullptr;
39 g_scFindNext=nullptr;
40 g_scHexSignature=nullptr;
41 g_scSignature=nullptr;
42 g_scHex=nullptr;
43
44 addColumn(tr("Address"),0,true);
45 addColumn(tr("Offset"));
46 addColumn(tr("Bytes"));
47 addColumn(tr("Opcode"));
48 addColumn(tr("Comment"));
49
50 setLastColumnScretch(true);
51
52 g_nAddressWidth=8;
53 g_nOpcodeSize=16;
54
55 setTextFont(getMonoFont());
56
57 setAddressMode(MODE_ADDRESS);
58
59 g_nCurrentIP=-1;
60 }
61
~XDisasmView()62 XDisasmView::~XDisasmView()
63 {
64 if(g_handle)
65 {
66 cs_close(&g_handle);
67 }
68 }
69
setData(QIODevice * pDevice,XDisasmView::OPTIONS options)70 void XDisasmView::setData(QIODevice *pDevice, XDisasmView::OPTIONS options)
71 {
72 g_options=options;
73
74 setDevice(pDevice);
75 setMemoryMap(g_options.memoryMap);
76 setSignaturesPath(g_options.sSignaturesPath);
77
78 XBinary::DM disasmMode=XBinary::getDisasmMode(getMemoryMap());
79
80 setMode(disasmMode);
81
82 adjustColumns();
83
84 qint64 nTotalLineCount=getDataSize()/g_nBytesProLine;
85
86 if(nTotalLineCount>1) // TODO Check
87 {
88 nTotalLineCount--;
89 }
90
91 setTotalLineCount(nTotalLineCount);
92
93 setCurrentIPAddress(options.nCurrentIPAddress);
94
95 if(options.nInitAddress)
96 {
97 qint64 nOffset=XBinary::addressToOffset(getMemoryMap(),options.nInitAddress);
98
99 if(nOffset==-1)
100 {
101 nOffset=0;
102 }
103
104 _goToOffset(nOffset);
105 }
106 else
107 {
108 setScrollValue(0);
109 }
110
111 reload(true);
112 }
113
setMode(XBinary::DM disasmMode)114 void XDisasmView::setMode(XBinary::DM disasmMode)
115 {
116 g_disasmMode=disasmMode;
117
118 g_mapOpcodes=XCapstone::getOpcodeColorMap(disasmMode);
119
120 XCapstone::closeHandle(&g_handle);
121 XCapstone::openHandle(disasmMode,&g_handle,true);
122 }
123
getMode()124 XBinary::DM XDisasmView::getMode()
125 {
126 return g_disasmMode;
127 }
128
setCurrentIPAddress(qint64 nAddress)129 void XDisasmView::setCurrentIPAddress(qint64 nAddress)
130 {
131 g_nCurrentIP=nAddress;
132 }
133
getSelectionInitAddress()134 qint64 XDisasmView::getSelectionInitAddress()
135 {
136 qint64 nResult=-1;
137
138 qint64 nOffset=getSelectionInitOffset();
139
140 if(nOffset!=-1)
141 {
142 nResult=XBinary::offsetToAddress(getMemoryMap(),nOffset);
143 }
144
145 return nResult;
146 }
147
_disasm(char * pData,qint32 nDataSize,qint64 nAddress)148 XDisasmView::DISASM_RESULT XDisasmView::_disasm(char *pData, qint32 nDataSize, qint64 nAddress)
149 {
150 DISASM_RESULT result={};
151
152 if(g_handle)
153 {
154 cs_insn *pInsn=0;
155
156 int nNumberOfOpcodes=cs_disasm(g_handle,(uint8_t *)pData,nDataSize,nAddress,1,&pInsn);
157 if(nNumberOfOpcodes>0)
158 {
159 QString sMnemonic=pInsn->mnemonic;
160 QString sStr=pInsn->op_str;
161
162 result.sOpcode+=sMnemonic;
163
164 if(sStr!="")
165 {
166 result.sOpcode+=QString(" %1").arg(sStr);
167 }
168
169 result.nSize=pInsn->size;
170
171 cs_free(pInsn, nNumberOfOpcodes);
172 }
173 else
174 {
175 result.sOpcode=tr("Invalid opcode");
176 result.nSize=1;
177 }
178 }
179 else
180 {
181 result.nSize=1;
182 }
183
184 return result;
185 }
186
getDisasmOffset(qint64 nOffset,qint64 nOldOffset)187 qint64 XDisasmView::getDisasmOffset(qint64 nOffset,qint64 nOldOffset)
188 {
189 qint64 nResult=nOffset;
190
191 if(nOffset!=nOldOffset)
192 {
193 qint64 nStartOffset=nOffset-5*g_nOpcodeSize;
194 qint64 nEndOffset=nOffset+5*g_nOpcodeSize;
195
196 nStartOffset=qMax(nStartOffset,(qint64)0);
197 nEndOffset=qMin(nEndOffset,getDataSize());
198
199 if(nOffset>nOldOffset)
200 {
201 nStartOffset=qMax(nStartOffset,nOldOffset);
202 }
203
204 qint32 nSize=nEndOffset-nStartOffset;
205
206 QByteArray baData=read_array(nStartOffset,nSize);
207
208 nSize=baData.size();
209
210 qint64 _nCurrentOffset=0;
211
212 // TODO nOffset<nOldOffset
213 while(nSize>0)
214 {
215 qint64 _nOffset=nStartOffset+_nCurrentOffset;
216
217 DISASM_RESULT disasmResult=_disasm(baData.data()+_nCurrentOffset,nSize,_nCurrentOffset);
218
219 if((_nOffset<=nOffset)&&(nOffset<_nOffset+disasmResult.nSize))
220 {
221 if(_nOffset==nOffset)
222 {
223 nResult=_nOffset;
224 }
225 else
226 {
227 if(nOffset>nOldOffset)
228 {
229 nResult=_nOffset+disasmResult.nSize;
230 }
231 else
232 {
233 nResult=_nOffset;
234 }
235 }
236
237 break;
238 }
239
240 _nCurrentOffset+=disasmResult.nSize;
241 nSize-=disasmResult.nSize;
242 }
243 }
244
245 return nResult;
246 }
247
getMenuState()248 XDisasmView::MENU_STATE XDisasmView::getMenuState()
249 {
250 MENU_STATE result={};
251
252 STATE state=getState();
253
254 // if(state.nCursorOffset!=XBinary::offsetToAddress(&(g_options.memoryMap),state.nCursorOffset))
255 // {
256 // result.bOffset=true;
257 // }
258
259 if(state.nSelectionSize)
260 {
261 result.bSize=true;
262 }
263
264 if(g_options.bMenu_Hex)
265 {
266 result.bHex=true;
267 }
268
269 return result;
270 }
271
drawText(QPainter * pPainter,qint32 nLeft,qint32 nTop,qint32 nWidth,qint32 nHeight,QString sText,TEXT_OPTION * pTextOption)272 void XDisasmView::drawText(QPainter *pPainter, qint32 nLeft, qint32 nTop, qint32 nWidth, qint32 nHeight, QString sText, TEXT_OPTION *pTextOption)
273 {
274 QRect rectText;
275
276 rectText.setLeft(nLeft+getCharWidth());
277 rectText.setTop(nTop+getLineDelta());
278 rectText.setWidth(nWidth);
279 rectText.setHeight(nHeight-getLineDelta());
280
281 bool bSave=false;
282
283 if((pTextOption->bCurrentIP))
284 {
285 bSave=true;
286 }
287
288 if(bSave)
289 {
290 pPainter->save();
291 }
292
293 if((pTextOption->bSelected)&&(!pTextOption->bCurrentIP))
294 {
295 pPainter->fillRect(nLeft,nTop,nWidth,nHeight,viewport()->palette().color(QPalette::Highlight));
296 }
297
298 if(pTextOption->bIsReplaced)
299 {
300 pPainter->fillRect(nLeft,nTop,nWidth,nHeight,QColor(Qt::red));
301 }
302 else if(pTextOption->bCurrentIP)
303 {
304 pPainter->fillRect(nLeft,nTop,nWidth,nHeight,viewport()->palette().color(QPalette::WindowText));
305 pPainter->setPen(viewport()->palette().color(QPalette::Base));
306 }
307
308 if(pTextOption->bHighlight)
309 {
310 drawDisasmText(pPainter,rectText,sText);
311 }
312 else
313 {
314 pPainter->drawText(rectText,sText);
315 }
316
317 if(bSave)
318 {
319 pPainter->restore();
320 }
321 }
322
drawDisasmText(QPainter * pPainter,QRect rect,QString sText)323 void XDisasmView::drawDisasmText(QPainter *pPainter, QRect rect, QString sText)
324 {
325 // TODO registers
326 QString sOpcode=sText.section(" ",0,0);
327
328 if(g_mapOpcodes.contains(sOpcode))
329 {
330 pPainter->save();
331
332 pPainter->setPen(g_mapOpcodes.value(sOpcode));
333 pPainter->drawText(rect,sOpcode);
334
335 pPainter->restore();
336
337 QString sOperands=sText.section(" ",1,-1);
338
339 if(sOperands!="")
340 {
341 QRect _rect=rect;
342 _rect.setX(rect.x()+QFontMetrics(pPainter->font()).size(Qt::TextSingleLine,sOpcode+" ").width());
343 pPainter->drawText(_rect,sOperands);
344 }
345 }
346 else
347 {
348 // TODO
349 pPainter->drawText(rect,sText);
350 }
351 }
352
cursorPositionToOS(XAbstractTableView::CURSOR_POSITION cursorPosition)353 XAbstractTableView::OS XDisasmView::cursorPositionToOS(XAbstractTableView::CURSOR_POSITION cursorPosition)
354 {
355 OS osResult={};
356 osResult.nOffset=-1;
357
358 if((cursorPosition.bIsValid)&&(cursorPosition.ptype==PT_CELL))
359 {
360 if(cursorPosition.nRow<g_listRecords.count())
361 {
362 qint64 nBlockOffset=g_listRecords.at(cursorPosition.nRow).nOffset;
363 qint64 nBlockSize=g_listRecords.at(cursorPosition.nRow).nSize;
364
365 if(cursorPosition.nColumn==COLUMN_ADDRESS)
366 {
367 osResult.nOffset=nBlockOffset;
368 osResult.nSize=nBlockSize;
369 }
370 else if(cursorPosition.nColumn==COLUMN_OFFSET)
371 {
372 osResult.nOffset=nBlockOffset;
373 osResult.nSize=nBlockSize;
374 }
375 else if(cursorPosition.nColumn==COLUMN_BYTES)
376 {
377 // TODO
378 osResult.nOffset=nBlockOffset;
379 osResult.nSize=nBlockSize;
380 }
381 else if(cursorPosition.nColumn==COLUMN_OPCODE)
382 {
383 osResult.nOffset=nBlockOffset;
384 osResult.nSize=nBlockSize;
385 }
386 else if(cursorPosition.nColumn==COLUMN_COMMENT)
387 {
388 osResult.nOffset=nBlockOffset;
389 osResult.nSize=nBlockSize;
390 }
391 }
392 else
393 {
394 if(!isOffsetValid(osResult.nOffset))
395 {
396 osResult.nOffset=getDataSize(); // TODO Check
397 osResult.nSize=0;
398 }
399 }
400 }
401
402 return osResult;
403 }
404
updateData()405 void XDisasmView::updateData()
406 {
407 g_listRecords.clear();
408
409 if(getDevice())
410 {
411 qint64 nBlockOffset=getViewStart()*g_nBytesProLine; // mb TODO remove BytesProLine!
412
413 qint32 nNumberLinesProPage=getLinesProPage();
414
415 qint64 nCurrentOffset=nBlockOffset;
416
417 for(int i=0;i<nNumberLinesProPage;i++)
418 {
419 if(nCurrentOffset<getDataSize())
420 {
421 qint32 nBufferSize=qMin(g_nOpcodeSize,qint32(getDataSize()-nCurrentOffset));
422
423 QByteArray baBuffer=read_array(nCurrentOffset,nBufferSize);
424
425 nBufferSize=baBuffer.size();
426
427 if(nBufferSize==0)
428 {
429 break;
430 }
431
432 RECORD record={};
433
434 qint64 nCurrentAddress=0;
435
436 if(getAddressMode()==MODE_ADDRESS)
437 {
438 nCurrentAddress=XBinary::offsetToAddress(getMemoryMap(),nCurrentOffset);
439 }
440 else if(getAddressMode()==MODE_RELADDRESS)
441 {
442 nCurrentAddress=XBinary::offsetToRelAddress(getMemoryMap(),nCurrentOffset);
443 }
444
445 record.nOffset=nCurrentOffset;
446 record.sOffset=QString("%1").arg(nCurrentOffset,g_nAddressWidth,16,QChar('0'));
447
448 record.nAddress=nCurrentAddress;
449
450 if(nCurrentAddress!=-1)
451 {
452 record.sAddress=QString("%1").arg(nCurrentAddress,g_nAddressWidth,16,QChar('0'));
453 }
454
455 DISASM_RESULT disasmResult=_disasm(baBuffer.data(),nBufferSize,nCurrentAddress);
456
457 record.sOpcode=disasmResult.sOpcode;
458 record.nSize=disasmResult.nSize;
459 nBufferSize=disasmResult.nSize;
460
461 baBuffer.resize(nBufferSize);
462 record.sHEX=baBuffer.toHex().data();
463
464 record.bIsReplaced=isReplaced(record.nOffset,record.nSize);
465
466 g_listRecords.append(record);
467
468 nCurrentOffset+=nBufferSize;
469 }
470 }
471
472 setCurrentBlock(nBlockOffset,(nCurrentOffset-nBlockOffset));
473 }
474 }
475
paintCell(QPainter * pPainter,qint32 nRow,qint32 nColumn,qint32 nLeft,qint32 nTop,qint32 nWidth,qint32 nHeight)476 void XDisasmView::paintCell(QPainter *pPainter, qint32 nRow, qint32 nColumn, qint32 nLeft, qint32 nTop, qint32 nWidth, qint32 nHeight)
477 {
478 qint32 nNumberOfRows=g_listRecords.count();
479
480 if(nRow<nNumberOfRows)
481 {
482 qint64 nOffset=g_listRecords.at(nRow).nOffset;
483 qint64 nAddress=g_listRecords.at(nRow).nAddress;
484
485 TEXT_OPTION textOption={};
486 textOption.bSelected=isOffsetSelected(nOffset);
487 textOption.bCurrentIP=((g_nCurrentIP!=-1)&&(nAddress==g_nCurrentIP)&&(nColumn==COLUMN_ADDRESS));
488 textOption.bIsReplaced=((g_listRecords.at(nRow).bIsReplaced)&&(nColumn==COLUMN_ADDRESS));
489 textOption.bHighlight=(nColumn==COLUMN_OPCODE);
490
491 if(nColumn==COLUMN_ADDRESS)
492 {
493 drawText(pPainter,nLeft,nTop,nWidth,nHeight,g_listRecords.at(nRow).sAddress,&textOption);
494 }
495 else if(nColumn==COLUMN_OFFSET)
496 {
497 drawText(pPainter,nLeft,nTop,nWidth,nHeight,g_listRecords.at(nRow).sOffset,&textOption);
498 }
499 else if(nColumn==COLUMN_BYTES)
500 {
501 drawText(pPainter,nLeft,nTop,nWidth,nHeight,g_listRecords.at(nRow).sHEX,&textOption);
502 }
503 else if(nColumn==COLUMN_OPCODE)
504 {
505 drawText(pPainter,nLeft,nTop,nWidth,nHeight,g_listRecords.at(nRow).sOpcode,&textOption);
506 }
507 else if(nColumn==COLUMN_COMMENT)
508 {
509 drawText(pPainter,nLeft,nTop,nWidth,nHeight,g_listRecords.at(nRow).sCommemt,&textOption);
510 }
511 }
512 }
513
contextMenu(const QPoint & pos)514 void XDisasmView::contextMenu(const QPoint &pos)
515 {
516 QAction actionGoToAddress(tr("Go to address"),this);
517 actionGoToAddress.setShortcut(getShortcuts()->getShortcut(XShortcuts::ID_DISASM_GOTOADDRESS));
518 connect(&actionGoToAddress,SIGNAL(triggered()),this,SLOT(_goToAddressSlot()));
519
520 QAction actionGoToOffset(tr("Go to offset"),this);
521 actionGoToOffset.setShortcut(getShortcuts()->getShortcut(XShortcuts::ID_DISASM_GOTOOFFSET));
522 connect(&actionGoToOffset,SIGNAL(triggered()),this,SLOT(_goToOffsetSlot()));
523
524 QAction actionGoToEntryPoint(tr("Go to entry point"),this);
525 actionGoToEntryPoint.setShortcut(getShortcuts()->getShortcut(XShortcuts::ID_DISASM_GOTOENTRYPOINT));
526 connect(&actionGoToEntryPoint,SIGNAL(triggered()),this,SLOT(_goToEntryPointSlot()));
527
528 QAction actionDumpToFile(tr("Dump to file"),this);
529 actionDumpToFile.setShortcut(getShortcuts()->getShortcut(XShortcuts::ID_DISASM_DUMPTOFILE));
530 connect(&actionDumpToFile,SIGNAL(triggered()),this,SLOT(_dumpToFileSlot()));
531
532 QAction actionHexSignature(tr("Hex signature"),this);
533 actionHexSignature.setShortcut(getShortcuts()->getShortcut(XShortcuts::ID_DISASM_HEXSIGNATURE));
534 connect(&actionHexSignature,SIGNAL(triggered()),this,SLOT(_hexSignatureSlot()));
535
536 QAction actionSignature(tr("Signature"),this);
537 actionSignature.setShortcut(getShortcuts()->getShortcut(XShortcuts::ID_DISASM_SIGNATURE));
538 connect(&actionSignature,SIGNAL(triggered()),this,SLOT(_signatureSlot()));
539
540 QAction actionFind(tr("Find"),this);
541 actionFind.setShortcut(getShortcuts()->getShortcut(XShortcuts::ID_DISASM_FIND));
542 connect(&actionFind,SIGNAL(triggered()),this,SLOT(_findSlot()));
543
544 QAction actionFindNext(tr("Find next"),this);
545 actionFindNext.setShortcut(getShortcuts()->getShortcut(XShortcuts::ID_DISASM_FINDNEXT));
546 connect(&actionFindNext,SIGNAL(triggered()),this,SLOT(_findNextSlot()));
547
548 QAction actionSelectAll(tr("Select all"),this);
549 actionSelectAll.setShortcut(getShortcuts()->getShortcut(XShortcuts::ID_DISASM_SELECTALL));
550 connect(&actionSelectAll,SIGNAL(triggered()),this,SLOT(_selectAllSlot()));
551
552 QAction actionCopyAsHex(tr("Copy as hex"),this);
553 actionCopyAsHex.setShortcut(getShortcuts()->getShortcut(XShortcuts::ID_DISASM_COPYASHEX));
554 connect(&actionCopyAsHex,SIGNAL(triggered()),this,SLOT(_copyAsHexSlot()));
555
556 QAction actionCopyCursorOffset(tr("Copy cursor offset"),this);
557 actionCopyCursorOffset.setShortcut(getShortcuts()->getShortcut(XShortcuts::ID_DISASM_COPYCURSOROFFSET));
558 connect(&actionCopyCursorOffset,SIGNAL(triggered()),this,SLOT(_copyCursorOffsetSlot()));
559
560 QAction actionCopyCursorAddress(tr("Copy cursor address"),this);
561 actionCopyCursorAddress.setShortcut(getShortcuts()->getShortcut(XShortcuts::ID_DISASM_COPYCURSORADDRESS));
562 connect(&actionCopyCursorAddress,SIGNAL(triggered()),this,SLOT(_copyCursorAddressSlot()));
563
564 QAction actionHex(tr("Hex"),this);
565 actionHex.setShortcut(getShortcuts()->getShortcut(XShortcuts::ID_DISASM_HEX));
566 connect(&actionHex,SIGNAL(triggered()),this,SLOT(_hexSlot()));
567
568 MENU_STATE menuState=getMenuState();
569
570 QMenu contextMenu(this);
571 QMenu menuGoTo(tr("Go to"),this);
572 QMenu menuSelect(tr("Select"),this);
573 QMenu menuCopy(tr("Copy"),this);
574
575 menuSelect.addAction(&actionSelectAll);
576
577 menuGoTo.addAction(&actionGoToAddress);
578 menuGoTo.addAction(&actionGoToOffset);
579 menuGoTo.addAction(&actionGoToEntryPoint);
580
581 menuCopy.addAction(&actionCopyCursorAddress);
582 menuCopy.addAction(&actionCopyCursorOffset);
583
584 if(menuState.bSize)
585 {
586 menuCopy.addAction(&actionCopyAsHex);
587 }
588
589 contextMenu.addAction(&actionFind);
590 contextMenu.addAction(&actionFindNext);
591
592 if(menuState.bSize)
593 {
594 contextMenu.addAction(&actionDumpToFile);
595 contextMenu.addAction(&actionSignature);
596 contextMenu.addAction(&actionHexSignature);
597 }
598
599 if(menuState.bHex)
600 {
601 contextMenu.addAction(&actionHex);
602 }
603
604 contextMenu.addMenu(&menuGoTo);
605 contextMenu.addMenu(&menuCopy);
606 contextMenu.addMenu(&menuSelect);
607
608 // TODO reset select
609
610 contextMenu.exec(pos);
611 }
612
wheelEvent(QWheelEvent * pEvent)613 void XDisasmView::wheelEvent(QWheelEvent *pEvent)
614 {
615 XAbstractTableView::wheelEvent(pEvent);
616 }
617
keyPressEvent(QKeyEvent * pEvent)618 void XDisasmView::keyPressEvent(QKeyEvent *pEvent)
619 {
620 XAbstractTableView::keyPressEvent(pEvent);
621 }
622
getScrollValue()623 qint64 XDisasmView::getScrollValue()
624 {
625 qint64 nResult=0;
626
627 qint32 nValue=verticalScrollBar()->value();
628
629 qint64 nMaxValue=getMaxScrollValue()*g_nBytesProLine;
630
631 if(getDataSize()>nMaxValue)
632 {
633 if(nValue==getMaxScrollValue())
634 {
635 nResult=getDataSize()-g_nBytesProLine;
636 }
637 else
638 {
639 nResult=((double)nValue/(double)getMaxScrollValue())*getDataSize();
640 }
641 }
642 else
643 {
644 nResult=(qint64)nValue*g_nBytesProLine;
645 }
646
647 qint64 _nResult=getDisasmOffset(nResult,getViewStart());
648
649 if(_nResult!=nResult)
650 {
651 nResult=_nResult;
652
653 setScrollValue(nResult);
654 }
655
656 return nResult;
657 }
658
setScrollValue(qint64 nOffset)659 void XDisasmView::setScrollValue(qint64 nOffset)
660 {
661 setViewStart(nOffset);
662
663 qint32 nValue=0;
664
665 if(getDataSize()>(getMaxScrollValue()*g_nBytesProLine))
666 {
667 if(nOffset==getDataSize()-g_nBytesProLine)
668 {
669 nValue=getMaxScrollValue();
670 }
671 else
672 {
673 nValue=((double)(nOffset)/((double)getDataSize()))*(double)getMaxScrollValue();
674 }
675 }
676 else
677 {
678 nValue=(nOffset)/g_nBytesProLine;
679 }
680
681 verticalScrollBar()->setValue(nValue);
682
683 adjust(true);
684 }
685
adjustColumns()686 void XDisasmView::adjustColumns()
687 {
688 setColumnEnabled(COLUMN_OFFSET,!(g_options.bHideOffset));
689
690 const QFontMetricsF fm(getTextFont());
691
692 if(XBinary::getWidthModeFromSize(getDataSize())==XBinary::MODE_64)
693 {
694 g_nAddressWidth=16;
695 setColumnWidth(COLUMN_ADDRESS,2*getCharWidth()+fm.boundingRect("0000000000000000").width());
696 setColumnWidth(COLUMN_OFFSET,2*getCharWidth()+fm.boundingRect("0000000000000000").width());
697 }
698 else
699 {
700 g_nAddressWidth=8;
701 setColumnWidth(COLUMN_ADDRESS,2*getCharWidth()+fm.boundingRect("00000000").width());
702 setColumnWidth(COLUMN_OFFSET,2*getCharWidth()+fm.boundingRect("00000000").width());
703 }
704
705 QString sBytes;
706
707 for(int i=0;i<g_nOpcodeSize;i++)
708 {
709 sBytes+="00";
710 }
711
712 setColumnWidth(COLUMN_BYTES,2*getCharWidth()+fm.boundingRect(sBytes).width());
713 setColumnWidth(COLUMN_OPCODE,40*getCharWidth());
714 setColumnWidth(COLUMN_COMMENT,40*getCharWidth());
715 }
716
registerShortcuts(bool bState)717 void XDisasmView::registerShortcuts(bool bState)
718 {
719 if(bState)
720 {
721 if(!g_scGoToAddress) g_scGoToAddress =new QShortcut(getShortcuts()->getShortcut(XShortcuts::ID_DISASM_GOTOADDRESS), this,SLOT(_goToAddressSlot()));
722 if(!g_scGoToOffset) g_scGoToOffset =new QShortcut(getShortcuts()->getShortcut(XShortcuts::ID_DISASM_GOTOOFFSET), this,SLOT(_goToOffsetSlot()));
723 if(!g_scGoToEntryPoint) g_scGoToEntryPoint =new QShortcut(getShortcuts()->getShortcut(XShortcuts::ID_DISASM_GOTOENTRYPOINT), this,SLOT(_goToEntryPointSlot()));
724 if(!g_scDumpToFile) g_scDumpToFile =new QShortcut(getShortcuts()->getShortcut(XShortcuts::ID_DISASM_DUMPTOFILE), this,SLOT(_dumpToFileSlot()));
725 if(!g_scSelectAll) g_scSelectAll =new QShortcut(getShortcuts()->getShortcut(XShortcuts::ID_DISASM_SELECTALL), this,SLOT(_selectAllSlot()));
726 if(!g_scCopyAsHex) g_scCopyAsHex =new QShortcut(getShortcuts()->getShortcut(XShortcuts::ID_DISASM_COPYASHEX), this,SLOT(_copyAsHexSlot()));
727 if(!g_scCopyCursorAddress) g_scCopyCursorAddress =new QShortcut(getShortcuts()->getShortcut(XShortcuts::ID_DISASM_COPYCURSORADDRESS), this,SLOT(_copyCursorAddressSlot()));
728 if(!g_scCopyCursorOffset) g_scCopyCursorOffset =new QShortcut(getShortcuts()->getShortcut(XShortcuts::ID_DISASM_COPYCURSOROFFSET), this,SLOT(_copyCursorOffsetSlot()));
729 if(!g_scFind) g_scFind =new QShortcut(getShortcuts()->getShortcut(XShortcuts::ID_DISASM_FIND), this,SLOT(_findSlot()));
730 if(!g_scFindNext) g_scFindNext =new QShortcut(getShortcuts()->getShortcut(XShortcuts::ID_DISASM_FINDNEXT), this,SLOT(_findNextSlot()));
731 if(!g_scSignature) g_scSignature =new QShortcut(getShortcuts()->getShortcut(XShortcuts::ID_DISASM_SIGNATURE), this,SLOT(_signatureSlot()));
732 if(!g_scHexSignature) g_scHexSignature =new QShortcut(getShortcuts()->getShortcut(XShortcuts::ID_DISASM_HEXSIGNATURE), this,SLOT(_hexSignatureSlot()));
733 if(!g_scHex) g_scHex =new QShortcut(getShortcuts()->getShortcut(XShortcuts::ID_DISASM_HEX), this,SLOT(_hexSlot()));
734 }
735 else
736 {
737 if(g_scGoToAddress) {delete g_scGoToAddress; g_scGoToAddress=nullptr;}
738 if(g_scGoToOffset) {delete g_scGoToOffset; g_scGoToOffset=nullptr;}
739 if(g_scGoToEntryPoint) {delete g_scGoToEntryPoint; g_scGoToEntryPoint=nullptr;}
740 if(g_scDumpToFile) {delete g_scDumpToFile; g_scDumpToFile=nullptr;}
741 if(g_scSelectAll) {delete g_scSelectAll; g_scSelectAll=nullptr;}
742 if(g_scCopyAsHex) {delete g_scCopyAsHex; g_scCopyAsHex=nullptr;}
743 if(g_scCopyCursorAddress) {delete g_scCopyCursorAddress; g_scCopyCursorAddress=nullptr;}
744 if(g_scCopyCursorOffset) {delete g_scCopyCursorOffset; g_scCopyCursorOffset=nullptr;}
745 if(g_scFind) {delete g_scFind; g_scFind=nullptr;}
746 if(g_scFindNext) {delete g_scFindNext; g_scFindNext=nullptr;}
747 if(g_scSignature) {delete g_scSignature; g_scSignature=nullptr;}
748 if(g_scHexSignature) {delete g_scHexSignature; g_scHexSignature=nullptr;}
749 if(g_scHex) {delete g_scHex; g_scHex=nullptr;}
750 }
751 }
752
_headerClicked(qint32 nNumber)753 void XDisasmView::_headerClicked(qint32 nNumber)
754 {
755 if(nNumber==COLUMN_ADDRESS)
756 {
757 if(getAddressMode()==MODE_ADDRESS)
758 {
759 setColumnTitle(COLUMN_ADDRESS,tr("Address"));
760 setAddressMode(MODE_RELADDRESS);
761 }
762 else if(getAddressMode()==MODE_RELADDRESS)
763 {
764 setColumnTitle(COLUMN_ADDRESS,tr("Relative address"));
765 setAddressMode(MODE_ADDRESS);
766 }
767
768 adjust(true);
769 }
770 }
771
_goToEntryPointSlot()772 void XDisasmView::_goToEntryPointSlot()
773 {
774 goToAddress(g_options.nEntryPointAddress);
775 setFocus();
776 viewport()->update();
777 }
778
_signatureSlot()779 void XDisasmView::_signatureSlot()
780 {
781 STATE state=getState();
782
783 DialogMultiDisasmSignature dmds(this);
784
785 dmds.setData(getDevice(),state.nSelectionOffset,getMemoryMap(),g_handle,g_options.sSignaturesPath);
786
787 dmds.setShortcuts(getShortcuts());
788
789 dmds.exec();
790 }
791
_hexSlot()792 void XDisasmView::_hexSlot()
793 {
794 if(g_options.bMenu_Hex)
795 {
796 // TODO
797 }
798 }
799