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