From 1584baabb16d8678a2a4d693c5d69f5c3e4d5230 Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Tue, 30 Jun 2026 15:57:09 -0400 Subject: [PATCH] GP-6987 - Instruction Pattern Searcher - Added new actions --- .../Base/data/ExtensionPoint.manifest | 1 + .../ghidra_scripts/YaraGhidraGUIScript.java | 6 +- .../Search/Search_Instruction_Patterns.htm | 14 +- .../images/SearchInstructionPatterns.png | Bin 30829 -> 35588 bytes ...rchInstructionPatternsInstructionTable.png | Bin 16677 -> 17125 bytes ...ructionPatternsInstructionTableToolbar.png | Bin 3376 -> 3798 bytes .../SearchInstructionPatternsPreviewTable.png | Bin 7872 -> 8565 bytes .../SearchInstructionsManualSearchDialog.png | Bin 7353 -> 8558 bytes .../InstructionSearchApi.java | 84 +++-- .../InstructionSearchPlugin.java | 9 +- .../model/InstructionSearchData.java | 340 +++++++++--------- .../model/MaskContainer.java | 56 +-- .../ui/InstructionSearchDialog.java | 169 ++++----- .../ui/InstructionSearchMainPanel.java | 19 +- .../ui/InstructionTable.java | 165 ++++++--- .../ui/InstructionTableCellRenderer.java | 2 +- .../ui/SearchInstructionsTask.java | 21 +- .../util/table/AddressPreviewTableModel.java | 51 +-- .../util/table/GhidraTableCellRenderer.java | 6 +- .../screenshot/GhidraScreenShotGenerator.java | 38 +- .../InstructionSearchTest.java | 19 +- .../FileFormats/data/ExtensionPoint.manifest | 1 - .../screenshot/AbstractSearchScreenShots.java | 11 +- .../InstructionPatternSearchScreenShots.java | 26 +- 24 files changed, 553 insertions(+), 485 deletions(-) diff --git a/Ghidra/Features/Base/data/ExtensionPoint.manifest b/Ghidra/Features/Base/data/ExtensionPoint.manifest index 711f68ce96..75640c0c6f 100644 --- a/Ghidra/Features/Base/data/ExtensionPoint.manifest +++ b/Ghidra/Features/Base/data/ExtensionPoint.manifest @@ -3,6 +3,7 @@ Demangler Exporter FieldFactory FieldMouseHandler +FileSystem StringHandler Loader SourceLanguage diff --git a/Ghidra/Features/Base/ghidra_scripts/YaraGhidraGUIScript.java b/Ghidra/Features/Base/ghidra_scripts/YaraGhidraGUIScript.java index 1ab0709218..bdec784ef7 100644 --- a/Ghidra/Features/Base/ghidra_scripts/YaraGhidraGUIScript.java +++ b/Ghidra/Features/Base/ghidra_scripts/YaraGhidraGUIScript.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -101,7 +101,7 @@ public class YaraGhidraGUIScript extends GhidraScript { state.getTool().showDialog(dialog); // Finally, load whatever instructions are selected in the listing. - dialog.loadInstructions(plugin); + dialog.loadInstructions(); } /********************************************************************************************* diff --git a/Ghidra/Features/Base/src/main/help/help/topics/Search/Search_Instruction_Patterns.htm b/Ghidra/Features/Base/src/main/help/help/topics/Search/Search_Instruction_Patterns.htm index 6c01549e03..681a8fdbfd 100644 --- a/Ghidra/Features/Base/src/main/help/help/topics/Search/Search_Instruction_Patterns.htm +++ b/Ghidra/Features/Base/src/main/help/help/topics/Search/Search_Instruction_Patterns.htm @@ -38,8 +38,9 @@ on an item in the table to mask it from the final search string.

Color-coding is used to indicate the code - unit type. Instructions are displayed in - blue, data items are tan.

+ unit type. + Instructions are displayed in blue, + data items are tan.

@@ -52,10 +53,12 @@

These tools provide ways to manipulate the Instruction Table and are discussed in detail below:

+

Provided by: InstructionSearchPlugin

+
+
+
diff --git a/Ghidra/Features/Base/src/main/help/help/topics/Search/images/SearchInstructionPatterns.png b/Ghidra/Features/Base/src/main/help/help/topics/Search/images/SearchInstructionPatterns.png index 7f2ac1a55dca5044b59995281a401fbd8a8e2147..786a8929cc80a93ea3015001d8bcebfff666906d 100644 GIT binary patch literal 35588 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 literal 30829 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 diff --git a/Ghidra/Features/Base/src/main/help/help/topics/Search/images/SearchInstructionPatternsInstructionTable.png b/Ghidra/Features/Base/src/main/help/help/topics/Search/images/SearchInstructionPatternsInstructionTable.png index 4df41f423b649f2a3875ab15b1b2540c3fb52146..27a2207234919e9a19379b5cc35841eb7f09eb62 100644 GIT binary patch literal 17125 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 literal 16677 zcmeHvcUV*Fx+jW=N>`C4AfTckEr3W9H1sMpfB~d;klu+{5Rl$G(xn9{p%%&zIX5#h|5^-I*X-cA@!tT`^4g4Mqn zR!_}a<1{_|;?#TOnX-q;E7efmLoGneFqotU?8*9hJiKQE?ZwxCVaPF4GvncXnc|TE zUf}y(dPe+7*xF9#^SH*O&(W$l?M=oK3_^?o*11uC7x%7=v8kMrQpj=d(S)H_WqRqc z70mq&gOyLo!w}b;^U{JbsMDsR$5B3>hjN1)R5E+9LUJf?o7upH#I}7DLwN7$zV=5i zby9kv+pMvIW6c4Kii09GUd$nLcCv4=hc0^5@2cjf%I#t`2v*r)iH}9YQi+KvK2nFZ zbzN^@LYun%#DF9pHY<+1cF;%8wJOwYlHRoB?P4Ypi^LACZ1tn$(OjR27c%Br^XF2=AJ?yL@2m zBDXeOt`H?XWvkHf0+z-O?{q5|7DY>?d-YSQe^LFRoC7VN7&>I4JbCi_6*Z(SE5$DSMV=$(y$Wu&b?>~Jvkc24K3zVcX3eTsXj{^~__4nGIqMC>`GsAKD^)lcAg>UvOZ z)AbaNRG*z(ubpnlCWi5Gbn<%_xi=Ohvw`uDHvLl%Yk@nA-rM0(_tnVRLn)~T8X4na zj0S++PxZeClV|2rLe$qz+%pZt@JTe#aPC`>#dB|{XqTC%tt38NjZ>fiU$}SiZG3#f zkG(08+jh1bCZ9?A*Pb<^pQ$>t+52gIX_)Yc9l|)(3@tvCacH#>u@vgy)$at8iC#Bn z3G&$^`%v^;+~++5$YECI4a3n^S;0v0xU7T{mPVSy>NL^8s^Kfhu=!Gxvp1paf$g4r zPc44QdaT`rrEJ54&AD?d+i>TlDyj<|tjuFp4YOHyO3c@pX+GzDadV}L8^Th4=9Pvg zxJ0*muD(G{cffWQiZXi#9+zN$o{B&BaT;1k^V^&Lz{Nnrr1U{R0!S{7nIfZ#h42+S z*>^l&&+~2*_lHbKNK|D{5mS-Tv4!>~aSFSvg`FJfv+Wd7G1-`*1fiJ~}vt5k>WvRhHWc zUIcp?s})S62#13Z`eSQ=i4(do5iU*e~1pn)fy#y!w2m)KpK zU}-p6WxbfJDdx5RxwhWs`R!kGEsxKo@wjNN&~Fx$kdtZI#G;WC(M2A8M?NNwLaU(b zwSId~vM~PY{#b=w>V2yG(xr;DL^D3cEyKAKukj&7=eux6R8&SrCkISmIccY6CpImE zF-Et>g`h)vZWy933Id%PNW=-7ydOHYPp-ra61G0R`iV-a1a+FxD;6PjjYvwN=mvH3 zkMolp-=Br>wA<$+TROZ?VvDlYQ&LI}n!Ybn`SFNNh-X;&2`T2Wfcd{v5p-eCiH`7f z4}x?wmv7Tl-8p(bG#qO|lwGGCG zEhV`>rtLnMbsC;FMID;M#3tyf7{Xraxwj@xBX+d69?D)MWfmKN&<$JQ%6DD`8SpJT zZG{Wf-$zkfi3zCX(F;$#7{OnyZg=|`9$;@1ovQ;br*irz_#A7$E!15jfrdsdA;k9k zpX6?d`;OVR3xb4h#y`||O0&R)p- z(DJ$sWz*XhD1__|nw<-~WRknPK74!O>&+^o4*Fsz{+6%LFUr@^?-+0I8O^T2zHyMC z_@dr4h*6t2Dckclf9_Aq`{d{La$dp6wgG#*=de{M(3)nt{~gR?vhU9`pAVY1-+y_q zR&r7FGPoK{bAU%BK^6j4cet17$IMa*&>LI%`X_P@QbnRdhMv36F+;g(ACt1<71{O1Ge+X7U8=Z! zHa_TI7>FVux)B%5b=n{+fEt}^{4`PScs#Xa#X{P>EY@U={tQIJ5<BT@}}lr)l54l)oOlzG)$nYyU9>8Gu%w5qN?vW^5QR@fY$yAumTV1f=;rT1iuJ zSjeObV$$RFiu@*Koq0UNi2VW-PGJ>d6+s5SNA}Yar55v53n`HoZHgk3THa50rTOGA z_&#j>)R(RXt*Huq%$~1V7&y0FoPE$~PG6HOF$;B!RkwmAcE$04^mJ| z*XyXvS%~?El4Qqcmbu*Z9Xx`?UegvfoV+g4!C}1MNj764_9w42y4JfZ+z3|lX1-(H zXRk)wJCOhPA}8XMQ~) zF<$UZ-o(VFc0gdq9U?tGw&h6==lR+XG<ZbM3S+UKXQWnWM4|YN`RP8|Lf;v z)|vWq__xg(N5r4|?y^3%>p<^BhV#C3nRfB!v+~yXXiKeOS1SOY)PN8yw-mZBIWN?6 zCJNY*Ms3Le6=B_LJ4Ah5rS40g<1Fh8jCu8LMdV?|l6=p85{v#Qs>nzrnq>kuGI5+J zP~*cEf^4weqBEp6kc(vk2zSN2eMeaU&$hQtvEjP{XcdUGC}bjp5J$8=cPn)Fwx+^f zbjFNkxLQ~I2+vcia_qX^?mkV~9$&wAPt7F((U|1vb9dN|{LGDb@2eBF$IZn3Kg9Nw%5v|<1Nl?!Shg^VeM)ySjLV$B(aOy+fn{*&jm1=(C?Tmb@fAxZ;2eTmzMjDf4KhI+8@)s}emihHzv^~|8vLbBFDmkZXMdp|+eWAQH_W-| zUjtvj!`m13yM%}L0?2SYyweaSKtfSFY-2A1Kck$2n3$t%F%4gz-kV^ChY?vo4gA~U z7c0YvC?IX`xFu%QouF;+{Ml!pQZqZS331LoZKiZ!BBl_eq^ELVn!Zv+?&qHr7(!G< zZvPH?2`r%`iF7v1!tx2yNkWsgOdNsRwLBZU`qBx?syTL5y4*kiTE2Bieh{C8H<+{X z`}u>@qxG4Aom!uhL+v9!lLS!l%;8QEjDud-CCXv0gJygG``0%v#X-;VdVR4At{~aw z;Q);ix3N;Q&@#IzJvQ}ExA-lG!XA4cwxwc^&1$rY)ureRBkw92cgAqoV-E9&6H-=4 zz)0oz5qt0LereT09sc;o-qi;P894-S`$=2AS@!mWzxMmRMeMECnu`kZ)J0746TXcDVy>f=0)^}}ogQnGjXmspRL zWCu+ax*s-RkHl!id}@dCG~_q8wz42adYiqlQ(pLKt@~EylQ$O~mU44C-cjk9``mQG z3}mV1DABifcJkUVJob8|xzKRB++h6k`&Wln8Z()lrQvR%$c`)QCLQsop0xy*YLuBpd+ zFs$nXF*yYeoidpoku8Px?rwgILzXImNw*AjI8>WWv*4bc`FzEkSzNNzZlu z9V-;v#_*vwat<=&&?4EaVcHxmhZXn~a)b8?jg3F;O-q@E{T40-^kki9cUAVd-)NRR z)xq|lvf@vX%{CT$sXSL3h^}+=@oq&!v|Yo=$c06KHZwx>*Izz9-8WK$O*aRq)_b`F zP#Ed8+0I&Ardg=dvh>LpVKc7z7<=ppULGk_{CV_i{;I*%|bDdlbL0P(98!e{Q7%}XY z*jy3pB%hd?TYRm08D1&WZYU)TT^Drcp+d|A>cA`gD?5TJRYi|hN*#8FA>-{Ws=!?H z08pkjQpMEnG`=I6*{n0-zp6aty_ZabaTmfKZ_T|Sd+eW#{Xqr`bLlur9SUK$teR$?Uh)t0gkrcRQa#tI zOrsJmcesIvEM#;mb?ZD3?%UaSY`|r6%7X&>y(dv@8f<0OLww0nJ1{)JQ4q<>OD!l= zP|bFR=A`;~%nBbEuiHh%l?c40fAmruU1njF-B>Gx4)>6w507K>n zipxi-ks+LoOKj;~ z2!`A)k=T$;i_zv~w2Rjf)!yf4vqlqD|^uII#SF__Ers zgxCmX*IgJ2PlH7oWM2YDu?Sa~b|;w3FF40W``CahNZv;WCu9#^!6zi;`+x~#ILe_{ z9o}Qa_F|7igKi2AbR8|1{X9O{`W?!-liqu}n7*_(NiJxMi>t&yq$F2@fMm86*JbRV zaP^3so{|K{g)X;Aq&b%aq)axr|L|N@UKl{sbewUQeX3kULZbVFx^b|?J=}!we>@8U>oB0}0&3T;!xOx>abN20C2KZWXXGPN`2p-o&NECU`DCCbes@ zj|xepnzZ~j7MrM5q1$HIN;on7oeGhNg`Di3m)Jy5;P2BI(WL6a=6gzpZ7>0JH zYkN(?1ps|LAuC}=6>}C7DV-SdTk;Y6aLwm%Vn#86H8PuFc&XE}=%bgu&pk;ZG*@fl zW-#*QGTo&;(cMR4A?#aSlVsh=?cauL&hIdlUS6(L^%mc58p&Ai6R&2Ze=-k&n;J^B z7dZ%RsJ*`Qfqhk4X!2!EyvCy$X*2nTv>Bt~?1fUuYEU#i-%{~tagX)zqph2c1=%l8 zy6Y6IF^cgFM`nmJ(bbQLhK}xTMfVAAzV(!}P`RB1Gx>wS0|!M^YQn=>5wUi-)isyy z&wOG+Y(pyP$teZFCeJ6id&fCrFV*;fmiWyd7{SVKyTFktSf|AS@Wqh08xWr_{<#A` z{1|*)uE@)Q)wc$IY)2jR#+6+zg(NyE?qSntMU>&=RF$u?End1WkZ{>BktxMdK}`GF zEKEJR;6(AtTFB@n{Pg0o7v9`4*4s+unyXvgZ9jdbO$j!cJTHG>uVcc>M$VgFFLfKt zcTkxzE!I+NQq34J>K?S%=jS>_C*=#~-j8?jBo!HG&Cak{RIGC)u_?0nkZ;mnS|nL* zOPxT)uK$YRi13<$a}(Su@>5FkymTxgp`vO;A^dKFZt=KQ{mv`(m&X1k%IvJ{UW3K# zDKIr9cF5P8cHj2ssy_e70p#e>X@hczTNC}Gs@4bd%!Z;rAq z!1i&$k2{imt=hElwMR6FWg#^j|b(%H8jZY)!S!C!QA<0Z`c$GjH2Y6 zyFV|F&&IG(n!WTWn4C^tUM%wnF6~06KVGVukW%qC_7^hwsHR%2lo2|4{WX>>KTiM7 zz$KOb`w)I9Q3he}Tt0Ir?T-w`ga-7G60)~fo!@>M)T?g&xM<$r^M2*d19%yDZ%PJJ zOl4&SJ55o~*BiXKOtQad@nP=x11%5R6&kF+~E5sDK=FHl@;;lwKa zid-HGa94=Ifd?||B}wsjg6$m4gw9NMVb?}WEFW*SIqJ>It%4c3opb&C&ExAdH)QrQ zTt}nxH3eF81#~?MmIGY`+msro<)pP8HS4H_Q9TokRvt5jgVvM8(T|rdK1rV5?vS8i zI!u+0T1K0vG}P+#!h%2ZHyW?rVZRm=b7f+qNUcNCqN%rdNV(kaQx~+nyCCB+pGEya zmnYrBK}lmUaZ_p$9j%j|wrfo5Du_d7un4-pj7bhzyE-K7rHfxO{%(Z{7$GI3dPdQV zlF!FUQ7XszZnrK~O#rAyp|{XTh_@&NE^nn^kut$x%xGYrr3S0coY7C*LMBXhEkha( zPmh}BkKtd96c;?qu!Ke?w)I=}mHZNQ1}H1{1B2qkrRs+X3tUAE!m<44C?Nbj^(`=0wLrMn2kA3svhX_X|9cPEv3-5ip>SZB?W`^*}R0M@s7A zIeDhQwUx3fJt{d)Laxi#Do30J_V}h$$_8;j!miuVpX^^ft|sk)t~#7q+Q{lne2h$7 z8|-HCSX<9Z4!>UAk`G8U?E)lchyYS*()g$x=dVT|+Q#Ka60l zE4>M}F+=?7bt>Fe{sg_U0@Q`*Q4^fA-lQ!IVVMQVEj z%v<21n?0qOe?nRS9_BUh3g7{+EAOkl9k{<*MlM%@BP=*Bv7OC~7Z^DC)w5&^?+TGU z0cT(373;hW5O7iH2{|Op7N8POUUWo#f9*8AUb!Ojs`2T6d^9lH>q49_&jBC(LjLu> z6ZHG}-<%}f1~Q%d~KmDVVE9byJDMs&9rhrs2ireBqdlPxKhJv(G1Gaw8;3 zttO?w;|Ii7qzwu@&*cFMF7imJlBB;S-46qEyvdYEqlj26Cq6GT za5YY|4R7_M$^b@0;63zLmNHU1pU_~7ViG(;I-4w3vKl&XYuOE<)_uhKfW*H~Vn4bs zIM3OkpF8<3*m!@x%KqGFo~{{Y#Pj9%^A)?aw+qp(JjlUV>+l4#WcI{8*iFcMd>vzg z@QF8wL!nw1=cZV zn+RPs>32eMWrH>=R_KErTE3WKvFBHXQAX>I-_qpCXdW5rKo8EbWXrv$^T;e%W?iX9 ze)wD|x8ntnDOrzgdRm}3v&aPBU;Pku%$76A6@5#UHa#I$X-Xj;8zh^^?THXXIl=HO zbGB!zy?u$y6E4QNPW~LYvHAV2yS>T9;3U&*o|WpbgSXC5kD2YryWJ)m^AMAbY{*=C zYqw!>reBs+7BV4cP{&H|7$FF8R8<45?%s6E3|5pL?@Q!br$y@x-hgyQnCX9T!lA2X zJ)Y?9)b_h!k{Y<8mMEF7srlr*4zFZ_wR%Jcd1s2IlBTsMyG#A_fxuju17+7nt9L^< z5uF}e6GO61&yGqjzo>?;m;p*u?`?}l-a>}=(CeMAk2|EKXAzdEc2a(1A|UoKvN3=# z{gp|0d`;ZlCVY{rnq_j5(&S6D_`do-Fo}zkW$zNtJ2Pzo1aU>>W5{u>7OkL38q|K+ zd450Sw5dC)MnE@5>WAXg@~3WF@c2#-qE526_U0ZmLRWye`vZG}gV}dl1LqY0&uHkl zlyf$QR;-dC`W;b%Eyu~a)q9FUmc*V6RatT^#7g}}CqW(yo#nMm!$8R$Ap|CsF{0=) zF(au39V^N`L0gJlACZ2iQls}Kb8sjuSpp=H95|4RpRA0MwzKSDw5Ht3m!M^06Pn9w z{e(2i;flT(%tO))pFIo~ z9|R@5Obii_i|l+(xEYC{GKtDzu`JBDvP9}YF4wGWFh78+il%;Ikx0%)Ijc!Ze{gwh z%=Mcyyw7r7H8|iv>!rGp6zeWj^3fCU*`hmc>U+uZ8U?zDwvhrjKyT8my<@ln750Wb zz>q{J&A9VkKKw*iCh6p3(sU~;@jYMm@pJ}BCV zmPe32avXbD+H=sCd7xTlxii{YanCtYch8OD1|&Bn6wWm1)B72q_THg8JI`i@65T~d zoF!{+8ncFz@DRi5IYl6!;_O`h${Og)*5(IjAZSqx7mff zu_p$OKB(`-*<1Cc*f+%>fhl+WZ?x%?S{Ov_@#j%RX8=C8Vo^JGSfMPXg+mhFejsh5 z`z@-Oj7;N5wFQ1Iaw?y&y@GSxwPY!%^C1gTu2gech3|DOdQKsTP%1bOy)ON z?^bSZcF>mb_6w`jq@*)?(A$IVgiin&D>MfergyH$3E3{g-$f40$fpVvr>Qx6)O#(T zb6g9(lU!fBn=RbU7nhDa#V86t%z&b#wz@b6Y0ct=s)+_0A~hNeGt~leyV~z+(@fN6 zTV;8GUyP6w!3*gEG;LtQ26P6i@#|M7T`Jst>d@`lb@ZM5#6`iI zb^sAfRR*Yw2fm|r=kEME=#08p^A)HKCfDp-hAvkpdM2#jLu10cZ}UsMO20Z{Z*s-O zOb05c(z_+03u&LNd_7GBfN1+{$g+gXKJsaLe;7LsLfii7ovEO|j9w_lGe;>|>9U(9ozYjpBCwB&-@B==omeXxX>klJDev4E?>U@un?)4jku> zD-M+}L@y+U|G*FJx-tvieGRNM&?5(MC=w^z+$^%>qGNVENeN$Ti1V%(+Y+>Rm;K*)k9jtmy;&!SoRFNCf_vJTthg^B_Rz z=}o>Ro?P7u-zUFn;;)aOeHW#r-7llai4?eg573!pW7pG9Dtm3(5bp24G?+zYcxltckUJ`BI&XmD<1n=>AE^9Z_!H%)1Pf$cpuOQmWu;A zT9m*(0MW?{#1CM&{X20T7{_FpBZ(xy7!D0dX3sFgZza3go46X|VQ@+Loo^IxfB@js zpM^oMoX7=C0-p(Gnfl}M@7M3V@SnU+C9cvRp7yutH*^C?Kfn8GFD3s^=3at(R){4XV6>H0r_sTDt9Tq1HTgY(XY~(b-Cp!o5RG3-j^Gwd>sKCnuG(+g?x&) zqE1=e&3hb7+zHFK|coiL>PR3Jv&cjo*U_Tsv=PRj%GBXBiZ z#@ruI@=g~J=~w=}$o^}^?jlDFrq8@~;;~#}9<--`gelclmYjvOnLq7ITI*lhbQA|2 z{)r&Td&#Q2689zse*X@DF@Zz?n6&jpCKEo>;)Ab*5Z|J|@Nn4e9N{x{C(93&ubrBr z?pHFu@OSwMnBl+)Qg^&}1pgkY5cpl{0U!rZ)|Jd@Ooy=U+P}ETm0yw&hVS|6SLC)j z=L7%e81K}to6)V>*!5A}>e5l2j}pmsIHYlKUk(AepZZlkT(Nr6e(qNgth)hnA)KXZ1P3tGK?`XD3UtDkcSotREV?Mo37iVoRQ6urJG|5vRh>s`@Dy* z{TB&1`|wuHR{$gdx~W}0M*;{XF_+2TTJ4sW-73F~4r2W(u8dzX^8aPCuCZ#+g-zf> zqRp=o;5@nCc|pmiUJeuW;-4*b0Cf4IvJS3wk3+4pWpKJMj4_Mk7c|}mLpN8f2GUn| zE^-yB=MI$k^!@-o$f^m5hqhJm-H0~wrk|S-001ktZ{9=n9rml}HS#x~AN+tmi*|`nT(<#`<%Kdf;=4HZaK*;o5wZ@l@~tlAvyHWQ zg0AJSVW|Ls$$(hJHIkHu7kr~&inVv;vggbIO2798*`zLeof(kXt3)K{=h|769fClx`RCaTfRdtF+AGDwlZy-iAY1pu+v9 zT;?xPcOHDf4A>cRW&bogQ+zsoMzy2_q> zNPHW^lr6`AOXCP8Hk_!OW1mO%JVz`)nD8JYy|7$ZcTqNfSC<(V6To3Zqn!}ftgid+ zmpjSTej&&od@4CaNkg>CR{xe3KSzTD0vF(_>fj-Y^d1qX)qZ78>ruY4pr;DaXE1gf zXeP7kB2{Y3{&45NR{QK7ss1H1WMcFIizy!AU3!+%Z!A!3yVC42c^U)A+Ssmq<>?LgE)uA|AL<2x(l0rqs8tEeCi zFr7gEffZ zeqM`7O-!^h%$6Kq##uy)K7ZTk#3>zFl73;m+5-)X$wOKTcjp`}^xtO+GW`C~ zkj<+=_QdH8;Yi+lCN{vVbN)s+109l*fhwIza>(UC?+;Mj| zAqh?>kBaXsZ;1{VAT?$UAm#~@IGAHoj{q8dbcrc;0QOK$yXqmDf1E|pSj^3S6QYtqF`O8;Y}wt&yJ<`X^n|F0 z9_pPg(XV#|SL{V5n2kh$a%N?t2YbUhpSwo2Zwb6DSIKqIu$V~8FZi~r`TZ~~`EAQE zaK0g&&f^=)TnB{DoY*2km+BS;V1xs>lI77|nzbHgKd;hza&Q`A4VYBMhY=hO6WyX` zaq_b1)QFRCOi~Lu7y6DH=>Oke6>^Srx7us-t7DAYr~dnn{taVR1N&jv=mnfUelYqo z;z{Vb=Szo=oZ`%?w9|k&srUk8pL|Hw8HbE%o?~75W{VMg25>otuDM$^mzFE9w!D5H za>Y5yJm&~#DF3E@&qzxmKUe0VJ{AX^j75xAF`yb2ul~alr^A<0h$a=-=0?)#AGU2v z4(Fkwjyr~Df!_Q@_~kKWIj}V#;flp+`5Y4Xs%o8~^%Feq577I8mkW$I&Sn^W?}iB9 z{I6CveCovKmRLdX+;cJ+0^;Ik@*9xq>!pnXHt-nSGGqOjMc*RG-C^P}aLi&SPUUGk;39BpH7K*G=RH{7yZLb8@Y8}2{g3Ek;k#rc zWdp3qPQPbdix8vZg6;IYnYXP2G)k62yjqvKckG(?j8yRH<{z5ug+3#04LUe9*i2sr zGAvILu0zcz@=%XD3pkcCQas)HdqkvxW)ejupgkjK(_Nmr`bP6IVERS`lZ)D}^0zfB6rE!M4rR7>)@;0w zkO!P8sW-cRRGvd|pBx8;kJ-nk$c007NJ~Bd$3|2h+@8VEueap_y?<4@Fj2s-FX0FL z$`Tt>*9YPYxoYsNQu0f|;RqaIpk!G7Xn02pfB)uBFAG6I78 z%M!l=VJ>xTd*;7j!azXGd-_*Q*ksF6o}`rS0iDp4rMf287DPYL|EgL-Cw3LX1ty)4 zb*2|`zC?5TWHcv&6$4@ zXW;I)Y&))}ImrnZdLQkc!!y3{j~3|oIYPW=(93{>DFk|zo~}mj^5q=fb;x-?b63kV zRryNc7gfg#!}VFMjtIE5>WP{fqeH#Y^DK$^>`d=nL+!0U+a2`n--} zdsq2{8Raelf0Jo^^$hu|RynG&7Q}N=AMMS3Km%Xt*uaPRuh-$| z({jwWCFsw{zGGwD&Hx$-cpTtfM(WQw0Xh-Z=tWkeMlAm(075 zMaJ^yCqmlEk=T^I2-l8w2cNGq zn-=)YbLVge$HQcA^EKa4Tt(lf2!`(vo2q;!izjsXw1pMOqC#=`&K56ic```!lpaR6}b!rAwr|NjQCF#mr^ m{_hV4FCaC5e>iY}rRgW{DASbT@;dH@n`vY^y1Fc#R8TXkg5-YZ z=#LVrsy|xybfF<{NwXc950bnXUSf?ya&Kj2!9pIBe?p24h$8!yTR;+G@;8jaB4|S3 zrn5Im)OV>1t8yjJEr2t}Em^k=r|mjC=vCFWezQyO)Y)0n{1m!pd&}vlP9RalC=d>C zM=S9(yU~@)|GC7>fVHqR!Eo+qg9KQd5)VzVKR5sq{UQ^!(4!|`-dn9Y1{(>b@i%j70G zxvOdsiUS@%eW-);o&hcAl(=JQOybx(~k`*89r2dUGg zpBrE^@~_rf^i(jY$E}2JXSZpah&nB)QQBCaK@uF>rAsvVa-{vMHtr()HCn=$ zC8XL~`R13Re`e;ee<``R8eU8(w;B>myEEiH)pucgJ(tOFZv^so!nQ$#vUQR>SyIkr z=T{UcitWqUk#|+EK-1-!2jE{quIOM^UXs9&a+n{rQ*Ae6o65x}Ll!-r7m2BSgps9p z+a{0;%kwGdVv7&Qcq_%vA$!n<8py4Qy&7C?Ew-`QYs35sDjT2m?_L&nHy=(;*#n^z=9! zPJYC;qu9rnlEla3hRT9U=X%bjl#Je?fxPC|Q{n!+wU*bT}fC{3?5Y zIzLLEy&$#&gk@50&=>^r;CRA8Z(fxvBg22W*NhBlI~*IH9&bm|3+dIu)7WW*U^ZvD zu3fa&@9H&RLTy6=WaWGFlAad5B@49qaz$o2 z@4RNa!xA!Qk>1+!$Ce5-><3yIuDHBfw*2*6BF znrQk~uSm88SAN4dz@$81Ma~Cdf6`CHQg5z=SAJuzL}bwQVwlKAoAnS$PSA=-6?wTe zO&0uPsLj$j2y~!)mXw42@DFPiG-3q3X zj*(G@5WCXO7Cxg-_!ib8_X-Z61csf794KF;} zMVYBGP2cIm;WL~~kTf?jGDJtD+ewVs>bPU=0XL#mhBO?ly?dN= zd4UO7d`8DfvC)b-5Lm!e{58tnO_S>}&77*(bFqYgq$Lkyvcoqfvh>_(q@S0AUqe)n zWcI2sZ^yQ*jJZI#$4|ziuf8#xnwkBYBZTgdCa>qEc}Mi}5Dcg*%K23&6EpWy({O4i zPz)2sj$h#U*yCG`HHQeb{kLJw;v5&lhYBa(9MKfe<_BCXzz@pRUDbdWO_tP&6W_G? zcjvH-|J-GM9+@7T$6RqzEPnn-kW^h={V{%TKGNksWm(-3;=jzM9E7^0r~So`IvW#Z zx2?x=tBYi8=f$?Huz4^YYQpF+EXQu7%lQX)EXB+_zV?lZh=1sxQJ|vs;`54nIcmyV zOt=b)0HbD(`I!(zjhHsBq5MwQnjISq%&;|EK`hpbZD@ErVZ#T#;t+WtFPj~r;R`ezSy+}6HKSV_CU z^|m>rKD~)Grl3X!3gQ!sX0<8>|BwyC*WQ_7`SNv^iun0D>jqb15=>q(E>p($>#n<`^Y6f+Vilj*HH_%FPRd36?Yg?aL)i)yR zql4`*y<3nUU9HoS)}yXe_g$L;j)xBS2`M-Q3TtdFEq6ZyEG#l|In>bAtHL7;I|`!EiQA9O2BK3^LIwu3JY}X- zW+knQwb2^>N+YRpB-?e2xGx9EV)fGc-5pJ}SxmU^3P_;m-H}?2f$2uq(=UF1K~j^{ zQkd#U`HEBg7X!YZ*f3+D@zxF#0fKO($DH+Mc9p-99D{r>8O^do3~gI22#@GA)*NLK zhI^#5(eqy?mP$TAKiOMb%TL$aBir_=QTt(i?03ygus~DW_}cBs?&Ph*v)n%_pj>T=+!@!LWNd!YhIX-pc!s4vWEk$IHY9TwfB%#*fC|r|L!Z%H`&(=^Tj#Ff0 zNHiO2+wH~+KQtbk9*3zZrSvMRrL+YkrPk0-xY8M)G0H?4X_{V%^Zijxlhv){9C}+0 zdtnWXtYMTx&N{VD#K8YoqioDW$f{r(gV ze$N$+`Y>a1quu~4-MAB|ZTR&4lit-7{!O2RmqqHKZ)b=-QClJ1N_FET zq9y9L(Bp*c(@jvEIm>jA-pZb4Cjd+8-N3_as87AR5F8xFQOw&;#wfhA+`iy0b1)+y zAwgS+Ds_eZp#E}rZ6}n{zOQ)%+QKMG#^YPIS#8hh-ouV*r8#ELnVbXsQzGcZcO}WWe*`{t{2eY(- z6j%Y5QVv{(i&q!4B+;PbUnCf)#<4OFAHRLeOXJl~y!Fz8T3Ah*;9E-O#lA0&tuU^d z(FU?UswMz*TJ_bo_B9IrRKoB7HA4Fw5bvLASa!Ymr K99{x@?e{-e-(#Hs delta 3374 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 literal 7872 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 D*{jyX diff --git a/Ghidra/Features/Base/src/main/help/help/topics/Search/images/SearchInstructionsManualSearchDialog.png b/Ghidra/Features/Base/src/main/help/help/topics/Search/images/SearchInstructionsManualSearchDialog.png index 5bc9bc711c9b7b296b049be3c88294d121b9826b..e1503744a36e8bbc838d9c8d6049cf7ec0d6df87 100644 GIT binary patch literal 8558 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 NuIU=-9m8n}Sz&K0%qQc~6349TwV6c` zDi*$@(B1p4OIol+u{V`vLeX%)>HaXt=fIQME1b6nWy_+_t*HKD-*Mww(8|rmes>^C z6)HG@YdDVbXg@n%T>5b$ZO_y)yF>&@{#z;6iS-(S5aQM*6we|bdnX04wY7ytu)}DH z2~{9O@6iZ!0mOE%Y~}Lu@_gj{?BE+%%Kw>e-P_E}vP8`5Vit=}S<>c~mWzxHp9Tlj zwY72UDOQP~wT+GILPb%OYhIDChwg+)js*Gs>E3G4$-s{?zuYopy@a${rTe1iuUrpbGA3`xmG&1VVUnG;@( z%b$X`-Pb1-PVNV#l=j8a&v%4|GE1MWR(zRRcx4)SdxAX#Uo* z_hK%!6>*(;d7rtfaSn@mgsSD;e_6_FR{MQiTeb~;R!xQLePH!0{POHuHs906Utd3j zDK#s?;Zh+vsV47{Do1sQsNSZ=+aTQGxVD;~G7p5i?c(ZW2`n9Gz@c9F{HfbOJWFE> zG;bM|=xoWMp86cU(G^aD4I+s`+7pwJQBPAv`*!T#A0I|jawW?4nJ<1A$~$@f1daY_39RLHM7Y!11Sur4kxW{`nL{iZ@1lVmtl&a zQ2Fjiq|}Rzp=O^SoLpQ2u{2;>FZo(Ltv+H(Q&7Q8Awg#X_0ZO&gan&BbH>@>bkR|^ z&r*%Ks&xnq)poC`larH}1!w#60!7#c+U!BN;YW~!nyV|fR7`AamZV=fIWV7^a77|! zxBY_5c(A{p|0fZvQli)O<=IM_+Kwd~jCQK^ISKM74k3z3NFYGgms#Vk<#MA0$6RQrIAd9Fklu)n6t@wbTuyKu}oOUWYYvkyN_ zcfb(a%(~5CcodVsYfy{{O-YOjncL@qp0B9nCoL-ydP&c37}ePJ=J9kjrWg!zx)2!{ z7`)r5sjlYdP`z*M@7GFYh#>B1QG$2&_I|rV^MnPGorE{x0)Yr^N1a}SuCsMFNcGHs3rYYpp!*b8_Mp4m-eiGX&+Hfc zY&`|`X^y1GPa+L3Y)_t^zcc!l|ARVKP8DQMPENqV22z)<)T)C)olKQz;dXkQJ4DlH zzTU0-@j#wgS1lz2Lu}Dq3%oX~IjVaEo*JW0VOb?K>E}d zN^-n3eV`csS4{9=d+@~&If#q;P<-~yekEyl4!-n!f5a+Hx2J@&a;t)Ia`Ls9uBMej z1DZ}rbBovArIf`0-#5_YIFg4H>uLcZ-Hlx*Cs4~^s_#=PdtJ^-Eo`mwib2Ue&-g$| zFNe13tY~kZ&=it1NB=JDp>OakKni^3>VdsNV{QucF#9&)f;4v<1(j|P5}tPOp3I1k zMx@?-!MPZnN>lZUlbgFoj!Wjn6HH_hO)&^S4BuPn6?U15#OsDa1k|3lc9O|wMBh$I zB}YGT#gIovM?VpXc}iJAUlptzo%0CU?ii0QR7xbvWsNFokt(lBuH65?;b@Tv+x{Fw zg2Z#*9K+DOK{*hmI|xwam?6;rj+>Q@ZIuPzKq~|R8+lT=b~DXspPc zWC2NJobr#is)f+*xSJeoxv199e^p4LFG^leTB~UfpFm5j0K8=qjm2U`3<&t2tAXWf zlDGJ?kDzOSjNHBBWG#Y3A_0~eV+-mjc2O10zFcBJn2=M&lM|~F0ndj1@e z{OLS&lc+E4!9gY_sprwIbF~AbqjAHoO2g_wtrJ7Nedrkia&*vm^NUv7WxZ-O|=volA}Va94LXCbhM-)u_y@&T;e= zOvX^>fL_9z<|vY0(ia$``!%U~wG1ePfgvlhtI6mu?s<@rKQEdz+iG2d5U+F zpwzTR3Bk<7L_kIt*$F&sZ*PA_WMyUbzkJ?6BONGoI5;#!B@ldZ48SOb+G=T$xqr*E z>xraD;k5wmJ>Y%XdE_>FEZ|bdivdkY)?TB9Z~@pvaQw5352YvsX-~2RiQ&eL8g$PqpkJrZK;sU z)7=gn!=#YoXGV^8xA}UL5<1xsx{}PPGV`TIubX=&_^QKUev&?02swB6a?iUync3MM zGdy4Ux4Z$p@h9T(66Vf^LcDl4MxZbWsrUF>%74QBvNo>1Nc%fP>XelP3` znf0ID2&*D_z{}lk2;Ufb`|1@wa~$>J=jP)9!lDaJOgwr98u<&*@%cIzwqEVGj}_BC zR1(FYP==stEXxmI=a+&{EaJq(#QcX+1ul+vC}G#9t8W?`Cs6$NSMAKq%mM=?@Bu*> zH&@7%38vixl)Uof`)IC+h={4FDU)WxId;~QU&PgMqV>(25kj8AP-dQTgZV(18shcq z=BB2}nee--Nof_zZy2n_KDR}?=CO#@azapiramQ)4ruHZXYD(!L0mI)gh&E8^$amD ze2cYT%iZy4lUl~>FHJ81Np)zI^8DHf#AZIL7+$6^zaLX&7tCbz5)-#X*|0V-+@^Ns zPmAi0#yn=LZ%=QRDjN6GwxFphCg7E1f)0bpJfngb#bnpKI-y~GDo_iF0TZn%A<_^L znJwa$76_q`pjk0L*g|s?PavmUr7U49JRq__qwyLN&Oo;w5tmd)Oq{c+4A(kB@cij~VfZ9Qrmz|I9OdFrVMB82qj_0ECtod9MX zjTdAUd}KJwQL6+=O4|j3M@2|)|f2Ayx6SMQUqDzqoeW4|<5c~Fe5uVJ0T$RVVvVS?}${$Upml25e6fj`-F9Bh?NNAK>5~c{~Cp-yGQ} z8K_Z|X0E~u*U-=?#n1po4G#}*Mf)^|2ymFMUcKru2b`ITs%n55jOp7H&)SgmjD$=* z1w;G6WW}B-26wtUHZULBtG>wtePXRn4$`->x6e=8kbgYeM`Yd$?r@cZyaCHvstb^T zWwtjqSlcG<@7GORnzzHx^g$r;26u>+snwLr*=mzlS4xM>Tr;Zx-+S4G!;4MY(9J&#haw`z7`{{U@gBSv zQjIb!as6h5^Y0vy#eJEYI-aSr5f>K+jw?XWg3KdgC8ebrng@(;w|Nq?qKYJ6a3-m5 z&LVZFf_cToA2P>=g@v77UhS_B`uh5Al;xHh_eVw&8gLNDR{1Y9`vk&rj1dtL>dTdt zl^pu{?~0|RrTumnH6hvLe`$ZDUswsw3^Ycex4`!Z`T3sf(TaI8;%}@!Oea5reUzb4 z*eps71a8Q5VY{=)T;(^^%dM?aK|w)#sgy$vsTS#T@kc3EA#WvoIJfc&3%`E|yAuf8 z3a`3hTJLIVW;O@>6@fxS0|U>2bN>O_#;vrU@xuI4#_REh2p722yVGlO8@3Jd8gK~+ z46Xq*~pm?bjVJ zoKcwi{O%O9rkP6HJ)h=JEz;hzxNY?_@pIcfu0g)97*+6AVSp5)h#By1c`}NL&9q8o zOZX7a>;Bn6!TQAg(hGwj+Hiw|Z3WM@{Fd-ChffNvwGBc(@rW(p;Hr^^HK65u0~3!UUTgOn)Yz8o%_7Gls=iy+onE5wESArfC)DSYnD*vo>`Z7Dpt2ta>cLEV)F5^@eF4P>R8;*kK+eQD zD^tv4QOe3{iS5&RO_}J1!oos84CCVBG>ue}2*pc^i}&~U^Q=_z(Qi%?j82v+Disky0QKCdV|&D$mAqgj8nDV_Hj=wZjFjI2QX@xT z$+fk$nVFf?)KrUP(!V1AaBl8-xYs_y21KpeO&) zs!Z#TMEp^W-#X&M4RuPS0g#nB*&-&;*ywU}DJh97?L)vAkhZ`v|6|+_%=^bcK!3Xn zz*hWr7r?Op&0hSY_8&ImxB2+rYyaU_evkZ*zW=EGuWkmALX&p@F!gt4Dx{DeYey^w zACi3YfAK#5IenU<^>HS~t0NZ4Nl#}gssuS^aH;fuEjaaGweoGL&rH=l)Yu< zyVd-H0tZ{$#Kc6Q*riS-c^x_`V#QoE_3%ol6wR4pueoILh1b#FogzP^@|Yae|Az5g z_f>3660uTxFJVu>%sT8;D43ZLvq&OpR!`t(NtBm)U7vB1hkGzpeK|0tC^)>&wTP~& zeWF!DRa3KftbC6M348BIHI}nyWh4-&zMh*aA+<3`Af}|86nh;MP*z^K?j_%&PBjd4 zP*bahw|pENf-uwx!LS#Z!flb6a?=U6&KF|=}S+~UkD;fAj3&VPY)QOodUMJ>})F?9dwby zA4HpV?;d;Fte1qAz2e2| zYDp3zTA>vSmUVYl?g%)r?+CeiYGL6pluAKCA>gw$5lb(L?dvm7L$lL{*E+((Lcz`L zYC$S^6h=OGk=%7Yj`JU9=gaGUpncZ2v?nAP^F{_=49P4o9!%mbH6E3+g$D5$%$;heqJQ}>S&rmHuM@UD%!vx9jLOG`rBU3ms>~%1zqr3G)JoV%ec<) zD=RC5!Cu~1UoKdT&om@ECnZ`L+<8GL*68#;_Z$IiOLkMCR3+!KEGX68#( zBel-svaMhITl>`I38hZ3*ks?>>uf2xMh{0M%B_R}oL@39@RAT^c|)-T3`vNO=V!p= z=YMRE9$tGZ=m4Y}8{(Li2?z+(B$^rhXL$_&5O3W))#m5+h^zMOb(2U6rfQ?{joTsNx|CUZ+~eXQ4|-EML1vkn~pC_F!p0Vjbcuqbf5TQ^6d+9y93TAaQ7{6sUBfaE0tZ4$d8QJ|eYC2gT_etv!oM>JA|yJo=7H6~gc z6~3LG4y1fkZa{x@pnIAbq~!~)Hlrh3yt$nL?`b(^2ywf(gY--hpA>xmtrE#a}%r zbW~KlZE0j=WKEx*nVFfIN(kYzXh!&K6zb*zw16TcIzQftwpc0BFCfQmu9V6!R0fHs9FPdO!rP2jjCldvMG12W-2^WaT1d z8DIM7D2QTuB#%hr%U2&e+8wQlbBwpPB5x{|h(bQRCVj-OJvTcW5ES&JQa+5}1AEUs zz>QB$)dOw^Fy~M30izd>4hRVFC$aNbXclG?IAH=kzDFlU-WBBUFD5A&da~g62hOzv zN*j%pRKYp$+#{Tt^C%y2MSW|T-mAg-w{;ic^voL;Sr zfwZ-z!1Tg&&PIwBDK2*aNURVO6FZ;nu!Prof58`K06R-L7=oEzX4lEOE?m(CjTnM) zJp#F7*bkFV{nUa#xrmw6{?2)8%(ij0m0{Rvm09C0fx;~Wr{!PWp*=alopRvUNtt!j zj-HL+-pg2?cxI;l_{`OR)%G~y=lAOmt9oBO)AQv=he{}2m)(I^;nY>(y^avE(`XDy z(2RR4)~6YJ)TSKaJ`+XeR=<#M3?|Ig@pvsQRG|e}qn^%Sg diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/InstructionSearchApi.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/InstructionSearchApi.java index 35c48ea3ca..22f6cf219b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/InstructionSearchApi.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/InstructionSearchApi.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -31,19 +31,23 @@ import ghidra.util.task.TaskMonitor; /** * API for users who wish to perform instruction searching without the GUI. - * + *

* Limitations: - * 1) Searches may only be performed on a single program. - * 2) Only a single address range may be searched for. - * + *

    + *
  1. 1) Searches may only be performed on a single program. + *
  2. 2) Only a single address range may be searched for. + *
+ *

* Results: * Can be returned in 2 ways: - * 1) As a list of addresses representing the location of search matches. - * 2) As a string (either binary or hex) representing the search string to be used. - * The latter results option is useful if using another tool to perform the search (ie yara). - * + *

    + *
  1. 1) As a list of addresses representing the location of search matches. + *
  2. 2) As a string (either binary or hex) representing the search string to be used. + *
+ * The latter results option is useful if using another tool to perform the search (i.e., Yara). + *

* Extending: - * This class may be extended to provide an api for specific searching formats. There is + * This class may be extended to provide an API for specific searching formats. There is * currently an extension for Yara: {@link InstructionSearchApi_Yara}. * */ @@ -54,10 +58,10 @@ public class InstructionSearchApi { * filtering of results is performed; all matches regardless of operand type will be * returned. * - * @param program - * @param addressRange + * @param program the program + * @param addressRange the addresses * @return a list of addresses indicating starting positions of matches. - * @throws InvalidInputException + * @throws InvalidInputException if there are no code units in the given addresses */ public final List

search(Program program, AddressRange addressRange) throws InvalidInputException { @@ -84,12 +88,12 @@ public class InstructionSearchApi { * Searches the given program for the instructions specified by the given address range, with * masking set according to the given {@link MaskSettings} object * - * @param program - * @param addressRange - * @param maskSettings + * @param program the program + * @param addressRange the addresses + * @param maskSettings the mask settings * * @return a list of addresses indicating starting positions of matches. - * @throws InvalidInputException + * @throws InvalidInputException if there are no code units in the given addresses */ public final List
search(Program program, AddressRange addressRange, MaskSettings maskSettings) throws InvalidInputException { @@ -127,10 +131,10 @@ public class InstructionSearchApi { /** * Returns a binary string representing the bytes in the address range provided. * - * @param program - * @param addressRange - * @return - * @throws InvalidInputException + * @param program the program + * @param addressRange the addresses + * @return the search string + * @throws InvalidInputException if there are no code units in the given addresses */ public final String getBinarySearchString(Program program, AddressRange addressRange) throws InvalidInputException { @@ -144,14 +148,15 @@ public class InstructionSearchApi { /** * Returns a hex version of the bytes representing the address range given. * - * @param program - * @param addressRange - * @return - * @throws InvalidInputException + * @param program the program + * @param addressRange the addresses + * @return the search string + * @throws InvalidInputException if there are no code units in the given addresses */ public final String getHexSearchString(Program program, AddressRange addressRange) throws InvalidInputException { - return InstructionSearchUtils.toHexNibblesOnly(getBinarySearchString(program, addressRange)).toString(); + String searchString = getBinarySearchString(program, addressRange); + return InstructionSearchUtils.toHexNibblesOnly(searchString).toString(); } /** @@ -160,11 +165,11 @@ public class InstructionSearchApi { * * Note: Masked bits will be represented by a '.' character. * - * @param maskSettings - * @param addressRange - * @param maskSettings - * @return - * @throws InvalidInputException + * @param program the program + * @param addressRange the addresses + * @param maskSettings the mask settings + * @return the search string + * @throws InvalidInputException if there are no code units in the given addresses */ public final String getBinarySearchString(Program program, AddressRange addressRange, MaskSettings maskSettings) throws InvalidInputException { @@ -190,16 +195,16 @@ public class InstructionSearchApi { /** * Returns a hex version of the bytes representing the address range given. * - * @param program - * @param addressRange - * @param maskSettings - * @return - * @throws InvalidInputException + * @param program the program + * @param addressRange the addresses + * @param maskSettings the mask settings + * @return the search string + * @throws InvalidInputException if there are no code units in the given addresses */ public final String getHexSearchString(Program program, AddressRange addressRange, MaskSettings maskSettings) throws InvalidInputException { - return InstructionSearchUtils.toHexNibblesOnly( - getBinarySearchString(program, addressRange, maskSettings)).toString(); + String searchString = getBinarySearchString(program, addressRange, maskSettings); + return InstructionSearchUtils.toHexNibblesOnly(searchString).toString(); } /** @@ -224,6 +229,7 @@ public class InstructionSearchApi { * instructions would be impossible otherwise. * * @param bytes binary or hex string representing the bytes to be loaded + * @param tool the tool */ public void loadInstructions(String bytes, PluginTool tool) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/InstructionSearchPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/InstructionSearchPlugin.java index 3189ec4c77..4179a7c9df 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/InstructionSearchPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/InstructionSearchPlugin.java @@ -68,7 +68,7 @@ import ghidra.util.task.TaskMonitorComponent; //@formatter:on public class InstructionSearchPlugin extends ProgramPlugin { - final static String SEARCH_ACTION_NAME = "Search Instruction Patterns"; + public static final String SEARCH_ACTION_NAME = "Search Instruction Patterns"; private TaskMonitor taskMonitor; @@ -201,8 +201,7 @@ public class InstructionSearchPlugin extends ProgramPlugin { } /** - * Returns true if the number of instructions selected is less or equal to - * MAX_SELECTION_SIZE. + * Returns true if the number of instructions selected is less or equal to MAX_SELECTION_SIZE. * * @param selection the program selection * @return true if the selection size is valid @@ -217,7 +216,7 @@ public class InstructionSearchPlugin extends ProgramPlugin { /** * Returns true if the user has selected one and only one range of * instructions. - * + *

* If there are multiple ranges, this could be for two reasons: 1) the user * has (via the mouse) selected more than one set of address ranges, or 2) * the user selects a single region but that region spans memory blocks; @@ -227,7 +226,7 @@ public class InstructionSearchPlugin extends ProgramPlugin { * * @param selection the program selection * @return true if the selection range is valid - * @throws InvalidInputException + * @throws InvalidInputException if the given selection is invalid */ private boolean isSelectionRangeValid(ProgramSelection selection) throws InvalidInputException { Set blockNames = new HashSet<>(); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/model/InstructionSearchData.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/model/InstructionSearchData.java index 11f21c083f..e70844a14c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/model/InstructionSearchData.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/model/InstructionSearchData.java @@ -17,7 +17,6 @@ package ghidra.app.plugin.core.instructionsearch.model; import java.util.*; -import ghidra.app.plugin.ProgramPlugin; import ghidra.app.plugin.core.instructionsearch.ui.AbstractInstructionTable.OperandState; import ghidra.app.plugin.core.instructionsearch.ui.InstructionSearchDialog; import ghidra.app.plugin.core.instructionsearch.ui.InstructionTable; @@ -29,6 +28,7 @@ import ghidra.program.model.lang.OperandType; import ghidra.program.model.listing.*; import ghidra.program.model.mem.Memory; import ghidra.program.model.mem.MemoryAccessException; +import ghidra.program.util.ProgramLocation; import ghidra.util.Msg; import ghidra.util.exception.CancelledException; import ghidra.util.exception.InvalidInputException; @@ -38,6 +38,7 @@ import ghidra.util.task.*; * This is the data model that {@link InstructionSearchDialog} instances use * when building their displays. */ +@SuppressWarnings("deprecation") public class InstructionSearchData extends Observable { // This is the entire set of instructions that will be searched on when/if the user @@ -68,10 +69,29 @@ public class InstructionSearchData extends Observable { table.getModel().addTableModelListener(e -> applyMasks(table)); } + /** + * Deletes the instruction at the given index + * @param table the table + * @param index the index + */ + public void deleteInstruction(InstructionTable table, int index) { + instructions.remove(index); + InstructionTableModel model = (InstructionTableModel) table.getModel(); + + @SuppressWarnings("rawtypes") + Vector data = model.getDataVector(); + data.remove(index); + + model.fireTableRowsDeleted(index, index); + + modelChanged(UpdateType.UPDATE); + } + /** * This method ensures that all mask settings in the dialog are applied to * the {@link #instructions} list. * + * @param table the table * @see InstructionSearchData */ public void applyMasks(InstructionTable table) { @@ -89,20 +109,18 @@ public class InstructionSearchData extends Observable { * * @param program the current program * @param addressRange the addresses to load instructions for - * @throws InvalidInputException if there's an error parsing the - * instructions + * @throws InvalidInputException if there's an error parsing the instructions */ public void load(Program program, AddressRange addressRange) throws InvalidInputException { - // first clear out any current instructions. - instructions.clear(); - // Do some initial checks on the program and addresses we want to load instructions // for. If these are invalid, no need to proceed. if (program == null || addressRange == null || addressRange.getLength() == 0) { return; } + instructions.clear(); + // Now we have to use the sleigh logger to parse each of the code units in the // requested address set. Listing listing = program.getListing(); @@ -149,69 +167,6 @@ public class InstructionSearchData extends Observable { modelChanged(UpdateType.RELOAD); } - private class LoadInstructionsTask extends Task { - - private Program program; - private AddressSetView addresses; - - public LoadInstructionsTask(Program program, AddressSetView addresses) { - super("Loading Instructions", true, true, true); - this.program = program; - this.addresses = addresses; - } - - @Override - public void run(TaskMonitor monitor) throws CancelledException { - - monitor.setIndeterminate(true); - - Listing listing = program.getListing(); - CodeUnitIterator it = listing.getCodeUnits(addresses, true); - while (it.hasNext()) { - if (monitor.isCancelled()) { - return; - } - - CodeUnit cu = it.next(); - - InstructionMetadata instructionMetadata; - - // If this CU is an instruction, we can use the Sleigh debug logger to build the - // mask info. If not, we don't need to create anything complex for masking - it's - // either on or off. - if (cu instanceof Instruction) { - SleighDebugLogger logger = - new SleighDebugLogger(program, cu.getAddress(), SleighDebugMode.VERBOSE); - if (logger.parseFailed()) { - Msg.showError(this, null, "Parsing error", - "Error parsing instruction: " + cu.toString()); - return; - } - - instructionMetadata = getInstructionMetadata(logger, cu); - if (instructionMetadata != null) { - instructions.add(instructionMetadata); - } - processOperands(logger, cu, instructionMetadata); - - } - else if (cu instanceof Data) { - try { - instructionMetadata = getInstructionMetadata(cu); - if (instructionMetadata != null) { - instructions.add(instructionMetadata); - } - } - catch (InvalidInputException e) { - Msg.showError(this, null, "Parsing error", - "Error parsing data: " + cu.toString()); - return; - } - } - } - } - } - /** * Clears out the instruction list in this model, and fires off a * notification to subscribers. @@ -390,15 +345,16 @@ public class InstructionSearchData extends Observable { } // Make sure the column isn't out of bounds. - if (col >= instructions.get(row).getOperands().size()) { + InstructionMetadata metadata = instructions.get(row); + List operands = metadata.getOperands(); + if (col >= operands.size()) { return; } - instructions.get(row) - .getOperands() - .get(col) - .setMasked( - table.getCellData(row, col + 1).getState().equals(OperandState.MASKED)); + OperandMetadata operandMetadata = operands.get(col); + InstructionTableDataObject data = table.getCellData(row, col + 1); + boolean isMasked = data.getState().equals(OperandState.MASKED); + operandMetadata.setMasked(isMasked); } /** @@ -425,8 +381,8 @@ public class InstructionSearchData extends Observable { * * @return the mask container object */ - private MaskContainer getAllMasks() { + private MaskContainer getAllMasks() { List masks = new ArrayList(); List values = new ArrayList(); @@ -510,12 +466,12 @@ public class InstructionSearchData extends Observable { byte[] value, boolean instruction) { MaskContainer masks = new MaskContainer(mask, value); - InstructionMetadata instructionMetadata = new InstructionMetadata(masks); + InstructionMetadata metadata = new InstructionMetadata(masks); - instructionMetadata.setAddr(codeUnit.getAddress()); - instructionMetadata.setTextRep(codeUnit.getMnemonicString()); - instructionMetadata.setIsInstruction(instruction); - return instructionMetadata; + metadata.setAddr(codeUnit.getAddress()); + metadata.setTextRep(codeUnit.getMnemonicString()); + metadata.setIsInstruction(instruction); + return metadata; } /** @@ -586,20 +542,24 @@ public class InstructionSearchData extends Observable { if (instruction == null) { return null; } - if (instruction.getMaskContainer() == null) { - return null; - } - if (instruction.getMaskContainer().getMask() == null || - instruction.getMaskContainer().getValue() == null) { + + MaskContainer maskContainer = instruction.getMaskContainer(); + if (maskContainer == null) { return null; } - // Now Create the mask/value arrays. Populating these is the main point of this method; these + byte[] mask = maskContainer.getMask(); + byte[] maskValue = maskContainer.getValue(); + if (mask == null || maskValue == null) { + return null; + } + + // Now Create the mask/value arrays. Populating these is the main point of this method; they // will be placed in the return object when we're done. Note that they're initialized to // be the size of the mask/value arrays in the given instruction; these are guaranteed // to be the correct size (if they're not, there's a serious problem). - byte[] tempMask = new byte[instruction.getMaskContainer().getMask().length]; - byte[] tempValue = new byte[instruction.getMaskContainer().getValue().length]; + byte[] tempMask = new byte[mask.length]; + byte[] tempValue = new byte[maskValue.length]; ////////////////// // MNEMONIC @@ -609,8 +569,8 @@ public class InstructionSearchData extends Observable { // mnemonic portion of the arrays set to 0 (they were set to 0 above, when initialized). If // not masked, then we need to put the actual mnemonic bytes in the temp/value arrays. if (!instruction.isMasked()) { - tempValue = instruction.getMaskContainer().getValue(); - tempMask = instruction.getMaskContainer().getMask(); + tempValue = maskValue; + tempMask = mask; } ////////////////// @@ -621,38 +581,32 @@ public class InstructionSearchData extends Observable { // mask/value to the main arrays depending on the mask setting. for (OperandMetadata operand : instruction.getOperands()) { - // If masked, then just leave the value of the bits at 0. Continue to the next - // operand. + // If masked, then just leave the value of the bits at 0. Continue to the next operand. if (operand.isMasked()) { continue; } // Now do some due diligence with null checks... - if (operand.getMaskContainer().getValue() == null || - operand.getMaskContainer().getMask() == null || tempValue == null || - tempMask == null) { + maskValue = operand.getMaskContainer().getValue(); + mask = operand.getMaskContainer().getMask(); + if (maskValue == null || mask == null || tempValue == null || tempMask == null) { continue; } // Everything looks good, so apply the operand masks. - tempValue = InstructionSearchUtils.byteArrayOr(tempValue, - operand.getMaskContainer().getValue()); - tempMask = - InstructionSearchUtils.byteArrayOr(tempMask, operand.getMaskContainer().getMask()); + tempValue = InstructionSearchUtils.byteArrayOr(tempValue, maskValue); + tempMask = InstructionSearchUtils.byteArrayOr(tempMask, mask); } - // Now create a new struct for the mask and return to the caller. - MaskContainer result; try { - result = new MaskContainer(tempMask, tempValue); + return new MaskContainer(tempMask, tempValue); } catch (IllegalArgumentException e) { // If we're here, then there's a problem with the mask/value arrays we used to - // create the mask container. Just return null. + // create the mask container. + Msg.error(this, e.getMessage(), e); return null; } - - return result; } /** @@ -673,8 +627,8 @@ public class InstructionSearchData extends Observable { // Now figure out the size of the final array we need to construct. We // could use ArrayList objects instead but that would be too inefficient. int totalLength = 0; - for (int i = 0; i < values.size(); i++) { - totalLength += values.get(i).length; + for (byte[] value : values) { + totalLength += value.length; } // This takes the masks and values from each command and concats them together to form @@ -704,66 +658,53 @@ public class InstructionSearchData extends Observable { /** * Searches through instructions in the given program for a specific byte - * pattern. If found, returns the instruction. i + * pattern. If found, returns the instruction. * - * @param program the program to search + * @param location the current program location * @param searchBounds the addresses to search - * @param taskMonitor the task monitor * @param forwardSearch if true, search through addresses forward + * @param monitor the task monitor * @throws IllegalArgumentException if there's a problem parsing addresses * @return the instruction, or null if not found */ - public InstructionMetadata search(ProgramPlugin plugin, AddressRange searchBounds, - TaskMonitor taskMonitor, boolean forwardSearch) { + public InstructionMetadata search(ProgramLocation location, AddressRange searchBounds, + boolean forwardSearch, TaskMonitor monitor) { - if (plugin == null || plugin.getCurrentProgram() == null) { - throw new IllegalArgumentException("Program provided to search is null"); - } + monitor = TaskMonitor.dummyIfNull(monitor); + Objects.requireNonNull(location); - // Do a quick check to make sure the search bounds are within the bounds of the - // program. - if (searchBounds.getMinAddress() - .compareTo( - plugin.getCurrentProgram().getMinAddress()) < 0 || - searchBounds.getMaxAddress() - .compareTo( - plugin.getCurrentProgram().getMaxAddress()) > 0) { + Program program = location.getProgram(); + + // make sure the search bounds are within the bounds of the program + + if (searchBounds.getMinAddress().compareTo(program.getMinAddress()) < 0 || + searchBounds.getMaxAddress().compareTo(program.getMaxAddress()) > 0) { throw new IllegalArgumentException( "Search bounds are not valid; must be within the bounds of the program."); } - MaskContainer maskContainer = this.getAllMasks(); - + MaskContainer maskContainer = getAllMasks(); if (InstructionSearchUtils.containsOnBit(maskContainer.getMask())) { if (forwardSearch) { - return searchForward(plugin, searchBounds, taskMonitor, maskContainer); + return searchForward(location, searchBounds, maskContainer, monitor); } - return searchBackward(plugin, searchBounds, taskMonitor, maskContainer); + return searchBackward(location, searchBounds, maskContainer, monitor); } return null; } - /** - * Searches for a specific byte pattern in the positive direction. - * - * @param plugin the instruction pattern search plugin - * @param searchBounds the addresses to search - * @param taskMonitor the task monitor - * @param maskContainer the bytes to search for - * @return the instruction, or null if not found - */ - private InstructionMetadata searchForward(ProgramPlugin plugin, AddressRange searchBounds, - TaskMonitor taskMonitor, MaskContainer maskContainer) { + private InstructionMetadata searchForward(ProgramLocation location, AddressRange searchBounds, + MaskContainer maskContainer, TaskMonitor monitor) { Address startAddress = searchBounds.getMinAddress(); Address endAddress = searchBounds.getMaxAddress(); - Address currentPosition = plugin.getProgramLocation().getByteAddress().next(); + Address currentPosition = location.getByteAddress().next(); - taskMonitor.setShowProgressValue(false);// no need to show the number of bytes - taskMonitor.setProgress(0); + monitor.setShowProgressValue(false);// no need to show the number of bytes + monitor.setProgress(0); // The maximum value for the monitor is the number of bytes to be checked - this will // NOT always be the size of the range passed-in. If the cursor is in the middle of @@ -773,7 +714,7 @@ public class InstructionSearchData extends Observable { if (currentPosition.compareTo(searchBounds.getMinAddress()) > 0) { max = searchBounds.getMaxAddress().subtract(currentPosition); } - taskMonitor.setMaximum(max); + monitor.setMaximum(max); // Move the cursor to the beginning of the range if it is currently short of it. We don't // want to search for any addresses that aren't in the search bounds. @@ -781,14 +722,15 @@ public class InstructionSearchData extends Observable { currentPosition = startAddress; } + Program program = location.getProgram(); while (currentPosition.compareTo(endAddress) < 0) { // Search program memory for the given mask and val. - currentPosition = plugin.getCurrentProgram() - .getMemory() - .findBytes(currentPosition, - endAddress, maskContainer.getValue(), maskContainer.getMask(), true, - taskMonitor); + Memory memory = program.getMemory(); + byte[] mask = maskContainer.getMask(); + byte[] maskValue = maskContainer.getValue(); + currentPosition = + memory.findBytes(currentPosition, endAddress, maskValue, mask, true, monitor); // If no match was found, currentPosition will be null. if (currentPosition == null) { @@ -796,8 +738,7 @@ public class InstructionSearchData extends Observable { } // Otherwise construct a new entry to put in our results table. - MaskContainer masks = - new MaskContainer(maskContainer.getMask(), maskContainer.getValue()); + MaskContainer masks = new MaskContainer(mask, maskValue); InstructionMetadata temp = new InstructionMetadata(masks); temp.setAddr(currentPosition); @@ -807,24 +748,15 @@ public class InstructionSearchData extends Observable { return null; } - /** - * Searches for a specific byte pattern in the reverse direction. - * - * @param plugin the instruction pattern search plugin - * @param searchBounds the addresses to search - * @param taskMonitor the task monitor - * @param maskContainer the bytes to search for - * @return the instruction, or null if not found - */ - private InstructionMetadata searchBackward(ProgramPlugin plugin, AddressRange searchBounds, - TaskMonitor taskMonitor, MaskContainer maskContainer) { + private InstructionMetadata searchBackward(ProgramLocation location, AddressRange searchBounds, + MaskContainer maskContainer, TaskMonitor monitor) { Address startAddress = searchBounds.getMaxAddress(); Address endAddress = searchBounds.getMinAddress(); - Address currentPosition = plugin.getProgramLocation().getByteAddress().previous(); + Address currentPosition = location.getByteAddress().previous(); - taskMonitor.setShowProgressValue(false); - taskMonitor.setProgress(0); + monitor.setShowProgressValue(false); + monitor.setProgress(0); // The maximum value for the monitor is the number of bytes to be checked - this will // NOT always be the size of the range passed-in. If the cursor is in the middle of @@ -834,7 +766,7 @@ public class InstructionSearchData extends Observable { if (currentPosition.compareTo(searchBounds.getMaxAddress()) < 0) { max = currentPosition.subtract(searchBounds.getMinAddress()); } - taskMonitor.setMaximum(max); + monitor.setMaximum(max); // Move the cursor to the end of the range if it is currently past it. We don't // want to search for any addresses that aren't in the search bounds. @@ -842,14 +774,15 @@ public class InstructionSearchData extends Observable { currentPosition = startAddress; } + Program program = location.getProgram(); while (currentPosition.compareTo(endAddress) > 0) { // Search program memory for the given mask and val. - currentPosition = plugin.getCurrentProgram() - .getMemory() - .findBytes(currentPosition, - endAddress, maskContainer.getValue(), maskContainer.getMask(), false, - taskMonitor); + Memory memory = program.getMemory(); + byte[] mask = maskContainer.getMask(); + byte[] maskValue = maskContainer.getValue(); + currentPosition = memory.findBytes(currentPosition, endAddress, maskValue, mask, false, + monitor); // If no match was found, currentPosition will be null. if (currentPosition == null) { @@ -857,8 +790,7 @@ public class InstructionSearchData extends Observable { } // Otherwise construct a new entry to put in our results table. - MaskContainer masks = - new MaskContainer(maskContainer.getMask(), maskContainer.getValue()); + MaskContainer masks = new MaskContainer(mask, maskValue); InstructionMetadata temp = new InstructionMetadata(masks); temp.setAddr(currentPosition); @@ -930,4 +862,68 @@ public class InstructionSearchData extends Observable { return searchResults; } + + private class LoadInstructionsTask extends Task { + + private Program program; + private AddressSetView addresses; + + public LoadInstructionsTask(Program program, AddressSetView addresses) { + super("Loading Instructions", true, true, true); + this.program = program; + this.addresses = addresses; + } + + @Override + public void run(TaskMonitor monitor) throws CancelledException { + + monitor.setIndeterminate(true); + + Listing listing = program.getListing(); + CodeUnitIterator it = listing.getCodeUnits(addresses, true); + while (it.hasNext()) { + if (monitor.isCancelled()) { + return; + } + + CodeUnit cu = it.next(); + + InstructionMetadata instructionMetadata; + + // If this CU is an instruction, we can use the Sleigh debug logger to build the + // mask info. If not, we don't need to create anything complex for masking - it's + // either on or off. + if (cu instanceof Instruction) { + SleighDebugLogger logger = + new SleighDebugLogger(program, cu.getAddress(), SleighDebugMode.VERBOSE); + if (logger.parseFailed()) { + Msg.showError(this, null, "Parsing error", + "Error parsing instruction: " + cu.toString()); + return; + } + + instructionMetadata = getInstructionMetadata(logger, cu); + if (instructionMetadata != null) { + instructions.add(instructionMetadata); + } + processOperands(logger, cu, instructionMetadata); + + } + else if (cu instanceof Data) { + try { + instructionMetadata = getInstructionMetadata(cu); + if (instructionMetadata != null) { + instructions.add(instructionMetadata); + } + } + catch (InvalidInputException e) { + Msg.showError(this, null, "Parsing error", + "Error parsing data: " + cu.toString()); + return; + } + } + } + } + } + } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/model/MaskContainer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/model/MaskContainer.java index ad33dfd967..e16786f7d4 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/model/MaskContainer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/model/MaskContainer.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -16,6 +16,7 @@ package ghidra.app.plugin.core.instructionsearch.model; import ghidra.app.plugin.core.instructionsearch.util.InstructionSearchUtils; +import ghidra.util.Msg; import ghidra.util.exception.InvalidInputException; /** @@ -26,12 +27,6 @@ public class MaskContainer { private byte[] mask; private byte[] value; - /** - * - * @param mask - * @param value - * @throws InvalidInputException - */ public MaskContainer(byte[] mask, byte[] value) throws IllegalArgumentException { // Mask and value arrays must be the same size, and not be null. @@ -48,79 +43,52 @@ public class MaskContainer { this.value = value; } - /** - * @return the mask - */ public byte[] getMask() { return mask; } - /** - * - * @return - */ public String getMaskAsBinaryString() { StringBuilder str = new StringBuilder(); - for (int i = 0; i < mask.length; i++) { - str.append(InstructionSearchUtils.toBinaryString(mask[i])); + for (byte element : mask) { + str.append(InstructionSearchUtils.toBinaryString(element)); } return str.toString(); } - /** - * @param mask the mask to set - */ public void setMask(byte[] mask) { this.mask = mask; } - /** - * @return the value - */ public byte[] getValue() { return value; } - /** - * - * @return - */ public String getValueAsBinaryString() { StringBuilder str = new StringBuilder(); - for (int i = 0; i < value.length; i++) { - str.append(InstructionSearchUtils.toBinaryString(value[i])); + for (byte element : value) { + str.append(InstructionSearchUtils.toBinaryString(element)); } return str.toString(); } - /** - * @param value the value to set - */ public void setValue(byte[] value) { this.value = value; } - /** - * Returns the bytes and masking merged together, as a binary string. - * - * @param mask - * @param value - * @return list containing the value (index 0) and mask (index 1). - */ public String toBinaryString() { StringBuilder valueString = new StringBuilder(); StringBuilder maskString = new StringBuilder(); - for (int i = 0; i < value.length; i++) { - valueString.append(InstructionSearchUtils.toBinaryString(value[i])); + for (byte element : value) { + valueString.append(InstructionSearchUtils.toBinaryString(element)); } - for (int i = 0; i < mask.length; i++) { - maskString.append(InstructionSearchUtils.toBinaryString(mask[i])); + for (byte element : mask) { + maskString.append(InstructionSearchUtils.toBinaryString(element)); } String combinedString = ""; @@ -129,7 +97,7 @@ public class MaskContainer { maskString.toString()); } catch (InvalidInputException e) { - e.printStackTrace(); + Msg.error(this, e.getMessage(), e); } return combinedString; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InstructionSearchDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InstructionSearchDialog.java index d15f6cd01e..fa82e32987 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InstructionSearchDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InstructionSearchDialog.java @@ -35,8 +35,7 @@ import ghidra.app.services.GoToService; import ghidra.app.util.HelpTopics; import ghidra.app.util.query.TableService; import ghidra.framework.plugintool.PluginTool; -import ghidra.program.model.address.Address; -import ghidra.program.model.address.AddressSet; +import ghidra.program.model.address.*; import ghidra.program.model.listing.Program; import ghidra.program.util.ProgramSelection; import ghidra.util.*; @@ -46,21 +45,8 @@ import ghidra.util.task.TaskLauncher; import ghidra.util.task.TaskMonitor; /** - * The GUI component for the {@link InstructionSearchPlugin}. This consists of two main panels - * for displaying instruction data, an area for control widgets, and a button panel: - * - * ------------------------------------ - * | | | - * | Instruction | Preview | - * | Panel | Panel | - * | | | - * |----------------------------------- - * | Control Widgets | - * ------------------------------------ - * | Button Panel | - * ------------------------------------ + * The GUI component for the {@link InstructionSearchPlugin}. */ - public class InstructionSearchDialog extends ReusableDialogComponentProvider implements Observer { private static final Color BG_COLOR_MARKERS = @@ -106,7 +92,7 @@ public class InstructionSearchDialog extends ReusableDialogComponentProvider imp try { revalidate(); - loadInstructions(plugin); + loadInstructions(); } catch (InvalidInputException e) { Msg.error(this, "Error loading instructions: " + e); @@ -121,32 +107,33 @@ public class InstructionSearchDialog extends ReusableDialogComponentProvider imp * Loads the currently-selected set of instructions in the listing and displays them in * the given dialog. * - * @param plugin the parent plugin * @throws InvalidInputException if there's a problem loading instructions */ - public void loadInstructions(InstructionSearchPlugin plugin) throws InvalidInputException { - loadInstructions(plugin.getProgramSelection(), plugin); + public void loadInstructions() throws InvalidInputException { + loadInstructions(plugin.getProgramSelection()); } /** * Loads the instructions in the given selection and displays them in the gui. * * @param selection the current selection - * @param plugin the parent plugin */ - public void loadInstructions(ProgramSelection selection, InstructionSearchPlugin plugin) { + public void loadInstructions(ProgramSelection selection) { MessagePanel msg = getMessagePanel(); if (selection == null && msg != null) { msg.setMessageText( "Select instructions from the listing (and hit reload) to populate the table.", Messages.NORMAL); + return; } - if (selection != null && plugin.isSelectionValid(selection, this)) { + if (plugin.isSelectionValid(selection, this)) { - if (getControlPanel() != null) { - getControlPanel().getRangeWidget().updateSearchRangeBySelection(); + ControlPanel panel = getControlPanel(); + if (panel != null) { + SelectionScopeWidget rangeWidget = panel.getRangeWidget(); + rangeWidget.updateSearchRangeBySelection(); } // Load the instructions, but note that we only allow a single selection range. If @@ -159,9 +146,8 @@ public class InstructionSearchDialog extends ReusableDialogComponentProvider imp * Adds the instructions in the given selection and displays them in the gui. * * @param selection the current selection - * @param plugin the parent plugin */ - public void addToInstructions(ProgramSelection selection, InstructionSearchPlugin plugin) { + public void addToInstructions(ProgramSelection selection) { MessagePanel msg = getMessagePanel(); if (selection == null && msg != null) { @@ -267,12 +253,12 @@ public class InstructionSearchDialog extends ReusableDialogComponentProvider imp plugin.firePluginEvent(new ProgramSelectionPluginEvent(plugin.getName(), selection, plugin.getCurrentProgram())); - SwingUtilities.invokeLater(() -> { + Swing.runLater(() -> { goToLocation(selection.getMinAddress()); try { - loadInstructions(selection, plugin); + loadInstructions(selection); } catch (Exception e) { Msg.error(this, "Error loading instructions", e); @@ -298,6 +284,13 @@ public class InstructionSearchDialog extends ReusableDialogComponentProvider imp getSearchData().clearAndReload(); } + void deleteInstruction(int index) { + InstructionSearchData data = getSearchData(); + InstructionTablePanel panel = getTablePanel(); + InstructionTable table = panel.getTable(); + data.deleteInstruction(table, index); + } + /** * Displays a message with the given text and color (severity). * @@ -317,26 +310,17 @@ public class InstructionSearchDialog extends ReusableDialogComponentProvider imp * UI to reflect the new instruction set, or simply update the preview panel in the case * where the user has simply changed the model by toggling masks. */ + @SuppressWarnings("deprecation") @Override public void update(Observable o, Object arg) { if (arg instanceof UpdateType) { UpdateType type = (UpdateType) arg; switch (type) { case RELOAD: - try { - revalidate(); - } - catch (InvalidInputException e) { - Msg.error(this, "Error loading instructions", e); - } + revalidate(); break; case UPDATE: - try { - tablePanel.buildPreview(); - } - catch (InvalidInputException e) { - Msg.error(this, "Error updating instructions", e); - } + tablePanel.buildPreview(); break; } } @@ -349,30 +333,18 @@ public class InstructionSearchDialog extends ReusableDialogComponentProvider imp /** * Updates the GUI when the user has made a new selection. For simplicity, this * removes the entire work panel and recreates it with the new instructions. - * - * @throws InvalidInputException */ - protected void revalidate() throws InvalidInputException { + protected void revalidate() { removeExistingGuiComponents(); createGuiComponents(); } - /** - * This dialog uses the 'apply' button as the search button, so override its behavior - * to initiate a search on activation. - */ @Override protected void applyCallback() { searchButtonActionPerformed(); } - /** - * Creates the main panel. - * - * @return the new panel - * @throws InvalidInputException if there's a problem constructing the panel - */ - protected JPanel createWorkPanel() throws InvalidInputException { + protected JPanel createWorkPanel() { // Create the main panel; use a border layout so all components // will adjust to fill the given space, allocating all leftover @@ -407,7 +379,7 @@ public class InstructionSearchDialog extends ReusableDialogComponentProvider imp * PRIVATE METHODS ********************************************************************************************/ - private void createGuiComponents() throws InvalidInputException { + private void createGuiComponents() { addWorkPanel(createWorkPanel()); createButtons(); @@ -492,33 +464,28 @@ public class InstructionSearchDialog extends ReusableDialogComponentProvider imp new TaskLauncher(searchTask, getFocusComponent()); } - /** - * Pops up a dialog containing the given search results. - * - * @param searchResults - */ public void displaySearchResults(List searchResults) { - Address[] tableArray = new Address[searchResults.size()]; - for (int x = 0; x < searchResults.size(); x++) { - tableArray[x] = searchResults.get(x).getAddr(); - } - TableService ts = plugin.getTool().getService(TableService.class); if (ts == null) { Msg.error(null, "Unable to show addresses, no table service available"); + return; } - else { - // The results window can be set to allow selection of multiple search results, - // provided the results are all the same size. This should be the case for us and - // as we're matching bytes, the size should always be divisible by 8. But do a check - // anyway. - int matchSize = 1; - if (searchData.getValueString().length() % 8 == 0) { - matchSize = searchData.getValueString().length() / 8; - } - show("Addresses", ts, tableArray, matchSize); + + Address[] tableArray = new Address[searchResults.size()]; + for (int i = 0; i < searchResults.size(); i++) { + tableArray[i] = searchResults.get(i).getAddr(); } + + // The results window can be set to allow selection of multiple search results, + // provided the results are all the same size. This should be the case for us and + // as we're matching bytes, the size should always be divisible by 8. But do a check + // anyway. + int matchSize = 1; + if (searchData.getValueString().length() % 8 == 0) { + matchSize = searchData.getValueString().length() / 8; + } + show("Addresses", ts, tableArray, matchSize); } /** @@ -529,20 +496,19 @@ public class InstructionSearchDialog extends ReusableDialogComponentProvider imp * @param addresses the list of addresses to display * @param matchSize the size of each match in the results table, in bytes */ - private void show(final String title, final TableService table, final Address[] addresses, - int matchSize) { - Runnable runnable = () -> { - AddressArrayTableModel model = new AddressArrayTableModel("Instruction Pattern Search", - plugin.getTool(), plugin.getCurrentProgram(), addresses); + private void show(String title, TableService table, Address[] addresses, int matchSize) { + + Swing.runLater(() -> { + + InstructionSearchTableModel model = + new InstructionSearchTableModel(addresses, matchSize); - model.setSelectionSize(matchSize); TableComponentProvider

tableProvider = table.showTableWithMarkers(title + " " + model.getName(), "Instruction Search Results", model, BG_COLOR_MARKERS, null, "Search", null); tableProvider.installRemoveItemsAction(); - }; - SystemUtilities.runSwingLater(runnable); + }); } private void goToLocation(Address addr) { @@ -553,4 +519,39 @@ public class InstructionSearchDialog extends ReusableDialogComponentProvider imp public InstructionSearchPlugin getPlugin() { return plugin; } + + private class InstructionSearchTableModel extends AddressArrayTableModel { + + private int matchSize; + + public InstructionSearchTableModel(Address[] addrs, int matchSize) { + super("Instruction Pattern Search", plugin.getTool(), plugin.getCurrentProgram(), + addrs); + this.matchSize = matchSize; + } + + @Override + public ProgramSelection getProgramSelection(int[] rows) { + if (matchSize == 1) { + return super.getProgramSelection(rows); + } + + int addOn = matchSize - 1; + AddressSet addressSet = new AddressSet(); + for (int element : rows) { + Address minAddr = getAddress(element); + Address maxAddr = minAddr; + try { + maxAddr = minAddr.addNoWrap(addOn); + addressSet.addRange(minAddr, maxAddr); + } + catch (AddressOverflowException e) { + Msg.debug(this, + "Unable to add address range for addresses: " + minAddr + ", " + maxAddr); + } + } + return new ProgramSelection(addressSet); + } + + } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InstructionSearchMainPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InstructionSearchMainPanel.java index 01ac50ea60..46d1643c02 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InstructionSearchMainPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InstructionSearchMainPanel.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -16,12 +16,12 @@ package ghidra.app.plugin.core.instructionsearch.ui; import java.awt.BorderLayout; +import java.util.Objects; import javax.swing.*; import ghidra.app.plugin.core.instructionsearch.InstructionSearchPlugin; import ghidra.app.plugin.core.instructionsearch.model.InstructionSearchData; -import ghidra.util.exception.InvalidInputException; /** * Container for the {@link InstructionTable} and {@link PreviewTable}. @@ -53,10 +53,9 @@ public class InstructionSearchMainPanel extends JPanel { * * @param plugin the instruction search plugin * @param dialog the parent dialog - * @throws InvalidInputException if the search data is invalid */ public InstructionSearchMainPanel(final InstructionSearchPlugin plugin, - InstructionSearchDialog dialog) throws InvalidInputException { + InstructionSearchDialog dialog) { super(new BorderLayout()); @@ -64,9 +63,7 @@ public class InstructionSearchMainPanel extends JPanel { // Get the number of operands we need to show (across all instructions); this // will define the number of columns to create. - if (searchData == null) { - throw new InvalidInputException("Search data object cannot be null"); - } + Objects.requireNonNull(searchData); int operands = searchData.getMaxNumOperands(); // Create the two main panels and link their scroll panes so they'll always @@ -100,10 +97,8 @@ public class InstructionSearchMainPanel extends JPanel { * Displays the current search strings based on all user settings. What is * displayed in the {@link PreviewTablePanel} is what will be used for any * subsequent searches. - * - * @throws InvalidInputException */ - public void buildPreview() throws InvalidInputException { + public void buildPreview() { previewTablePanel.buildPreview(); } @@ -128,7 +123,7 @@ public class InstructionSearchMainPanel extends JPanel { * * @param panel1 left panel * @param panel2 right panel - * @return + * @return the split pane */ private JSplitPane splitPanels(JPanel panel1, JPanel panel2) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InstructionTable.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InstructionTable.java index 32418ed56d..81cf926f68 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InstructionTable.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InstructionTable.java @@ -27,12 +27,15 @@ import generic.theme.GThemeDefaults.Colors.Messages; import ghidra.app.plugin.core.instructionsearch.InstructionSearchPlugin; import ghidra.app.plugin.core.instructionsearch.model.*; import ghidra.app.services.GoToService; +import ghidra.app.util.HelpTopics; import ghidra.program.model.address.Address; import ghidra.program.model.lang.OperandType; import ghidra.util.HelpLocation; import ghidra.util.Msg; import ghidra.util.exception.InvalidInputException; import ghidra.util.task.*; +import help.Help; +import help.HelpService; import resources.Icons; import resources.ResourceManager; @@ -85,10 +88,47 @@ public class InstructionTable extends AbstractInstructionTable { // The data model will want to know when items in this table change...so have it register. // This will trigger the model to be updated as the user is toggling mask settings. dialog.getSearchData().registerForGuiUpdates(this); + + addMouseListener(new MouseAdapter() { + @Override + public void mousePressed(MouseEvent e) { + maybePopup(e); + } + + @Override + public void mouseReleased(MouseEvent e) { + maybePopup(e); + } + + private void maybePopup(MouseEvent e) { + if (e.isPopupTrigger()) { + showPopup(e); + } + } + + private void showPopup(MouseEvent e) { + + int row = rowAtPoint(e.getPoint()); + if (row < 0) { + return; + } + + JPopupMenu popup = new JPopupMenu(); + JMenuItem menuCopy = new JMenuItem("Delete Instruction"); + menuCopy.addActionListener(event -> { + dialog.deleteInstruction(row); + }); + popup.add(menuCopy); + + popup.show(e.getComponent(), e.getX(), e.getY()); + } + + }); } @Override protected boolean supportsPopupActions() { + // this controls the built-in actions, such as copy return false; } @@ -128,26 +168,27 @@ public class InstructionTable extends AbstractInstructionTable { @Override protected JToolBar createToolbar() { - JToolBar toolbar1 = new JToolBar(); - toolbar1.add(Box.createHorizontalGlue()); + JToolBar newToolBar = new JToolBar(); + newToolBar.add(Box.createHorizontalGlue()); - createMaskClearAllBtn(toolbar1); - toolbar1.addSeparator(); - createMaskDataBtn(toolbar1); - createMaskOperandsBtn(toolbar1); - createMaskScalarsBtn(toolbar1); - createMaskAddressesBtn(toolbar1); - toolbar1.addSeparator(); - createReloadBtn(toolbar1); - createAddBtn(toolbar1); - toolbar1.addSeparator(); - createManualEditBtn(toolbar1); - toolbar1.addSeparator(); - createGoToAddressBtn(toolbar1); + createDeleteAllBtn(newToolBar); + createMaskClearAllBtn(newToolBar); + newToolBar.addSeparator(); + createMaskDataBtn(newToolBar); + createMaskOperandsBtn(newToolBar); + createMaskScalarsBtn(newToolBar); + createMaskAddressesBtn(newToolBar); + newToolBar.addSeparator(); + createReloadBtn(newToolBar); + createAddBtn(newToolBar); + newToolBar.addSeparator(); + createManualEditBtn(newToolBar); + newToolBar.addSeparator(); + createGoToAddressBtn(newToolBar); - toolbar1.setFloatable(false); + newToolBar.setFloatable(false); - return toolbar1; + return newToolBar; } /** @@ -287,6 +328,13 @@ public class InstructionTable extends AbstractInstructionTable { createToolbarButton(buttonToolbar, icon, action, "nav button"); } + private void createDeleteAllBtn(JToolBar buttonToolbar) { + Icon icon = Icons.DELETE_ICON; + Icon scaledIcon = ResourceManager.getScaledIcon(icon, ICON_SIZE, ICON_SIZE); + Action action = new DeleteAllAction("undefined", scaledIcon, "Delete all"); + createToolbarButton(buttonToolbar, icon, action, "delete all button"); + } + private void createMaskClearAllBtn(JToolBar buttonToolbar) { Icon icon = Icons.CLEAR_ICON; Icon scaledIcon = ResourceManager.getScaledIcon(icon, ICON_SIZE, ICON_SIZE); @@ -298,7 +346,8 @@ public class InstructionTable extends AbstractInstructionTable { Icon icon = Icons.REFRESH_ICON; Icon scaledIcon = ResourceManager.getScaledIcon(icon, ICON_SIZE, ICON_SIZE); Action action = - new ReloadAction("undefined", scaledIcon, "Load selected instructions from listing"); + new ReloadAction("undefined", scaledIcon, + "Reload using selected instructions from listing"); createToolbarButton(buttonToolbar, icon, action, "reload"); } @@ -306,8 +355,8 @@ public class InstructionTable extends AbstractInstructionTable { Icon icon = Icons.ADD_ICON; Icon scaledIcon = ResourceManager.getScaledIcon(icon, ICON_SIZE, ICON_SIZE); Action action = - new AddAction("undefined", scaledIcon, "Add selected instructions from listing"); - createToolbarButton(buttonToolbar, icon, action, "add"); + new AddAction("undefined", scaledIcon, "Append selected instructions from listing"); + createToolbarButton(buttonToolbar, icon, action, "append"); } private void createManualEditBtn(JToolBar buttonToolbar) { @@ -357,6 +406,11 @@ public class InstructionTable extends AbstractInstructionTable { button.setName(name); button.setHideActionText(true); toolbar1.add(button); + + //Instruction_Pattern_Actions + HelpLocation loc = new HelpLocation(HelpTopics.SEARCH, "Instruction_Pattern_Actions"); + HelpService help = Help.getHelpService(); + help.registerHelp(button, loc); } private void processInstruction(InstructionTableDataObject[][] dataObjects, @@ -388,6 +442,19 @@ public class InstructionTable extends AbstractInstructionTable { } + private class DeleteAllAction extends AbstractAction { + + public DeleteAllAction(String text, Icon icon, String desc) { + super(text, icon); + putValue(SHORT_DESCRIPTION, desc); + } + + @Override + public void actionPerformed(ActionEvent e) { + dialog.clear(); + } + } + private class ClearMasksAction extends AbstractAction { public ClearMasksAction(String text, Icon icon, String desc) { @@ -411,7 +478,7 @@ public class InstructionTable extends AbstractInstructionTable { @Override public void actionPerformed(ActionEvent e) { try { - dialog.loadInstructions(plugin); + dialog.loadInstructions(); } catch (InvalidInputException e1) { Msg.error(this, "Error loading instructions: " + e); @@ -428,7 +495,7 @@ public class InstructionTable extends AbstractInstructionTable { @Override public void actionPerformed(ActionEvent e) { - dialog.addToInstructions(plugin.getProgramSelection(), plugin); + dialog.addToInstructions(plugin.getProgramSelection()); } } @@ -442,7 +509,8 @@ public class InstructionTable extends AbstractInstructionTable { @Override public void actionPerformed(ActionEvent e) { insertBytesWidget = getInsertBytesWidget(); - plugin.getTool().showDialog(insertBytesWidget, plugin.getSearchDialog().getComponent()); + JComponent dialogComponent = dialog.getComponent(); + plugin.getTool().showDialog(insertBytesWidget, dialogComponent); } } @@ -512,12 +580,12 @@ public class InstructionTable extends AbstractInstructionTable { @Override public void actionPerformed(ActionEvent e) { - GoToService gs = plugin.getTool().getService(GoToService.class); // Only go somewhere if something is actually in the table. If it's empty this makes // no sense. Note that the plugin.getInstructions() call can never be null, so no // need to check that here. - if (dialog.getSearchData().getInstructions().size() <= 0) { + List instructions = searchData.getInstructions(); + if (instructions.size() <= 0) { return; } @@ -526,19 +594,25 @@ public class InstructionTable extends AbstractInstructionTable { // manually (hence no actual location in the listing). In this case, just search // for the first instance of this instruction and navigate there. If search returns // no results, display a message to the user. - Address firstAddr = dialog.getSearchData().getInstructions().get(0).getAddr(); - - if (firstAddr != null) { - gs.goTo(firstAddr); - } - else { - if (dialog.getMessagePanel() != null) { - dialog.getMessagePanel() - .setMessageText( - "Instruction was loaded manually, no address in the listing to navigate to.", - Messages.NORMAL); + Address firstAddr = instructions.get(0).getAddr(); + if (firstAddr == null) { + MessagePanel messagePanel = dialog.getMessagePanel(); + if (messagePanel != null) { + messagePanel.setMessageText( + "Instruction was loaded manually, no address in the listing to navigate to.", + Messages.NORMAL); } + return; } + + GoToService service = plugin.getTool().getService(GoToService.class); + if (service == null) { + Msg.showError(this, null, "Missing GoToSerivce", + "Cannot navigate without the GoToService installed"); + return; + } + + service.goTo(firstAddr); } } @@ -553,9 +627,11 @@ public class InstructionTable extends AbstractInstructionTable { */ private InstructionTableDataObject[][] processMnemonic(int row, int col, InstructionTableDataObject[][] dataObjects) { + + List instructions = searchData.getInstructions(); dataObjects[row][col] = new InstructionTableDataObject( - dialog.getSearchData().getInstructions().get(row).getTextRep(), - dialog.getSearchData().getInstructions().get(row).isInstruction(), + instructions.get(row).getTextRep(), + instructions.get(row).isInstruction(), OperandState.NOT_MASKED); return dataObjects; @@ -580,19 +656,18 @@ public class InstructionTable extends AbstractInstructionTable { // First get the operand information (if any exist) for this instruction. // Note, the getOperands() call will never return null so we're safe here. - List operands = - dialog.getSearchData().getInstructions().get(row).getOperands(); + List instructions = searchData.getInstructions(); + InstructionMetadata metadata = instructions.get(row); + List operands = metadata.getOperands(); if (operands.size() > col - 1) { - operandMetadata = - dialog.getSearchData().getInstructions().get(row).getOperands().get(col - 1); + operandMetadata = metadata.getOperands().get(col - 1); } // If here then we have a valid operand, so store it. if (operandMetadata != null) { InstructionTableDataObject obj = new InstructionTableDataObject(operandMetadata.getTextRep(), - dialog.getSearchData().getInstructions().get(row).isInstruction(), - OperandState.NOT_MASKED); + metadata.isInstruction(), OperandState.NOT_MASKED); obj.setOperandCase(operandMetadata); dataObjects[row][col] = obj; } @@ -602,7 +677,7 @@ public class InstructionTable extends AbstractInstructionTable { // NA will cause it to not be able to be toggled on/off by the user. else { dataObjects[row][col] = new InstructionTableDataObject("", - dialog.getSearchData().getInstructions().get(row).isInstruction(), OperandState.NA); + metadata.isInstruction(), OperandState.NA); } return dataObjects; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InstructionTableCellRenderer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InstructionTableCellRenderer.java index 874ca09384..3b203e007b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InstructionTableCellRenderer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/InstructionTableCellRenderer.java @@ -34,7 +34,7 @@ public class InstructionTableCellRenderer extends GhidraTableCellRenderer { private static final String FONT_ID = "font.plugin.instruction.table.renderer"; public InstructionTableCellRenderer() { - super(Gui.getFont(FONT_ID)); + setBaseFontId(FONT_ID); } /** diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/SearchInstructionsTask.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/SearchInstructionsTask.java index d3902ba782..40c5dfe8bf 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/SearchInstructionsTask.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/instructionsearch/ui/SearchInstructionsTask.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,12 +20,14 @@ import java.util.*; import generic.theme.GThemeDefaults.Colors.Messages; import ghidra.app.plugin.core.instructionsearch.InstructionSearchPlugin; import ghidra.app.plugin.core.instructionsearch.model.InstructionMetadata; +import ghidra.app.plugin.core.instructionsearch.model.InstructionSearchData; import ghidra.app.plugin.core.instructionsearch.ui.SearchDirectionWidget.Direction; import ghidra.app.services.GoToService; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressRange; import ghidra.program.model.listing.*; import ghidra.program.util.BytesFieldLocation; +import ghidra.program.util.ProgramLocation; import ghidra.util.Swing; import ghidra.util.task.Task; import ghidra.util.task.TaskMonitor; @@ -58,10 +60,9 @@ class SearchInstructionsTask extends Task { } @Override - public void run(TaskMonitor taskMonitor) { - if (taskMonitor == null) { - return; - } + public void run(TaskMonitor monitor) { + + monitor = TaskMonitor.dummyIfNull(monitor); // First get all the search ranges we have to search. List searchRanges = @@ -107,16 +108,18 @@ class SearchInstructionsTask extends Task { } if (searchRanges.size() > 1) { - taskMonitor.setMessage( + monitor.setMessage( "Searching range " + rangeNum + " of " + searchRanges.size()); } else { - taskMonitor.setMessage("Searching..."); + monitor.setMessage("Searching..."); } // And SEARCH. + ProgramLocation location = searchPlugin.getProgramLocation(); + InstructionSearchData searchData = searchDialog.getSearchData(); InstructionMetadata searchResults = - searchDialog.getSearchData().search(searchPlugin, range, taskMonitor, forward); + searchData.search(location, range, forward, monitor); // If there are results, move the cursor there, otherwise keep looping and check // the next range. diff --git a/Ghidra/Features/Base/src/main/java/ghidra/util/table/AddressPreviewTableModel.java b/Ghidra/Features/Base/src/main/java/ghidra/util/table/AddressPreviewTableModel.java index 99036c3fbb..7b39e37838 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/util/table/AddressPreviewTableModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/util/table/AddressPreviewTableModel.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -16,10 +16,8 @@ package ghidra.util.table; import ghidra.framework.plugintool.ServiceProvider; -import ghidra.program.model.address.*; +import ghidra.program.model.address.Address; import ghidra.program.model.listing.Program; -import ghidra.program.util.ProgramSelection; -import ghidra.util.Msg; import ghidra.util.task.TaskMonitor; /** @@ -31,8 +29,6 @@ import ghidra.util.task.TaskMonitor; */ public abstract class AddressPreviewTableModel extends AddressBasedTableModel
{ - private int selectionSize = 1; - /** * Constructor. * @@ -60,49 +56,8 @@ public abstract class AddressPreviewTableModel extends AddressBasedTableModel clazz = getClass(); String simpleName = clazz.getSimpleName(); @@ -339,11 +351,31 @@ public abstract class GhidraScreenShotGenerator extends AbstractScreenShotGenera writeFile(imageFile); } - protected File getHelpTopicDir(String helpTopic) { + protected File getHelpTopicDir(String topicName) { + return getHelpTopicDir(null, topicName); + } + + protected File getHelpTopicDir(String moduleName, String helpTopic) { List helpTopicDirs = getHelpTopicDirs(); for (File file : helpTopicDirs) { File potential = new File(file, helpTopic); - if (potential.exists()) { + if (!potential.exists()) { + continue; + } + + if (StringUtils.isBlank(moduleName)) { + return potential; // any module will do + } + + // Module/src/main/help/help/topics/TopicName + File topics = potential.getParentFile(); + File help = topics.getParentFile(); + File helpParent = help.getParentFile(); + File main = helpParent.getParentFile(); + File src = main.getParentFile(); + File module = src.getParentFile(); + String actualModuleName = module.getName(); + if (actualModuleName.equals(moduleName)) { return potential; } } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/instructionsearch/InstructionSearchTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/instructionsearch/InstructionSearchTest.java index 03c453441f..8d3d1956b0 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/instructionsearch/InstructionSearchTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/instructionsearch/InstructionSearchTest.java @@ -228,7 +228,7 @@ public class InstructionSearchTest extends AbstractGhidraHeadedIntegrationTest { // Now create a selection to add an instruction and call 'add' createSelection("0x004065e6", "0x004065e6"); - pressButtonByName(component, "add"); + pressButtonByName(component, "append"); waitForTasks(); // grab the rebuilt table @@ -237,6 +237,21 @@ public class InstructionSearchTest extends AbstractGhidraHeadedIntegrationTest { assertInstructionValue(8, "PUSH EAX"); } + @Test + public void testDeleteAll() throws Exception { + + // sanity check + assertEquals(8, instructionTable.getRowCount()); + assertInstructionValue(0, "INC EDI"); + assertInstructionValue(7, "MOV dword ptr [EBP + -0x4] EAX"); + + pressButtonByName(component, "delete all button"); + waitForTasks(); + + instructionTable = dialog.getTablePanel().getTable(); + assertEquals(0, instructionTable.getRowCount()); + } + /** * Tests that the {@link PreviewTable} is properly loaded when instructions are selected. */ @@ -695,6 +710,7 @@ public class InstructionSearchTest extends AbstractGhidraHeadedIntegrationTest { @Test public void testManualInsert_Invalid() { + setErrorsExpected(true); loadBytes("0000 abcd efgh 01011"); instructionTable = dialog.getTablePanel().getTable(); @@ -706,6 +722,7 @@ public class InstructionSearchTest extends AbstractGhidraHeadedIntegrationTest { Window errorDialog = waitForWindowByTitleContaining("Input Error"); assertNotNull(errorDialog); runSwing(() -> errorDialog.setVisible(false)); + setErrorsExpected(false); } /** diff --git a/Ghidra/Features/FileFormats/data/ExtensionPoint.manifest b/Ghidra/Features/FileFormats/data/ExtensionPoint.manifest index aebb112e35..9714ddd282 100644 --- a/Ghidra/Features/FileFormats/data/ExtensionPoint.manifest +++ b/Ghidra/Features/FileFormats/data/ExtensionPoint.manifest @@ -1,4 +1,3 @@ Decryptor -FileSystem FileSystemModel FSBFileHandler diff --git a/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/AbstractSearchScreenShots.java b/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/AbstractSearchScreenShots.java index 64c94b879d..dce2cf4d74 100644 --- a/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/AbstractSearchScreenShots.java +++ b/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/AbstractSearchScreenShots.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -28,6 +28,13 @@ import generic.theme.GThemeDefaults.Colors.Palette; protected static final Color NAVY = Palette.getColor("navy"); protected static final Color DARK_GREEN = Palette.getColor("darkgreen"); + @Override + protected String getHelpTopicModuleName() { + // Most Search help is in Base; some is in Docking. If the Docking help needs screenshots, + // then it will have to override this override. + return "Base"; + } + @Override protected String getHelpTopicName() { return "Search"; diff --git a/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/InstructionPatternSearchScreenShots.java b/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/InstructionPatternSearchScreenShots.java index 8d8a913cb9..73e81be603 100644 --- a/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/InstructionPatternSearchScreenShots.java +++ b/Ghidra/Test/IntegrationTest/src/screen/java/help/screenshot/InstructionPatternSearchScreenShots.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -25,6 +25,8 @@ import org.junit.Test; import docking.DialogComponentProvider; import docking.action.DockingActionIf; import generic.test.AbstractGuiTest; +import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin; +import ghidra.app.plugin.core.codebrowser.CodeViewerProvider; import ghidra.app.plugin.core.instructionsearch.InstructionSearchPlugin; import ghidra.app.plugin.core.instructionsearch.ui.*; import ghidra.app.plugin.core.table.TableComponentProvider; @@ -35,6 +37,7 @@ import ghidra.app.plugin.core.table.TableComponentProvider; public class InstructionPatternSearchScreenShots extends AbstractSearchScreenShots { private InstructionSearchPlugin instructionSearchPlugin; + private CodeViewerProvider codeViewer; @Override @Before @@ -44,6 +47,9 @@ public class InstructionPatternSearchScreenShots extends AbstractSearchScreenSho instructionSearchPlugin = env.getPlugin(InstructionSearchPlugin.class); + CodeBrowserPlugin cbp = env.getPlugin(CodeBrowserPlugin.class); + codeViewer = cbp.getProvider(); + env.showTool(); } @@ -52,7 +58,7 @@ public class InstructionPatternSearchScreenShots extends AbstractSearchScreenSho DockingActionIf openSearchDialogAction = getAction(instructionSearchPlugin, "Search Instruction Patterns"); - performAction(openSearchDialogAction, true); + performAction(openSearchDialogAction, codeViewer, true); waitForSwing(); @@ -78,7 +84,7 @@ public class InstructionPatternSearchScreenShots extends AbstractSearchScreenSho DockingActionIf openSearchDialogAction = getAction(instructionSearchPlugin, "Search Instruction Patterns"); - performAction(openSearchDialogAction, true); + performAction(openSearchDialogAction, codeViewer, true); waitForSwing(); captureDialog(DialogComponentProvider.class, 900, 461); @@ -96,7 +102,7 @@ public class InstructionPatternSearchScreenShots extends AbstractSearchScreenSho DockingActionIf openSearchDialogAction = getAction(instructionSearchPlugin, "Search Instruction Patterns"); - performAction(openSearchDialogAction, true); + performAction(openSearchDialogAction, codeViewer, true); waitForSwing(); Component instrTable = @@ -117,7 +123,7 @@ public class InstructionPatternSearchScreenShots extends AbstractSearchScreenSho DockingActionIf openSearchDialogAction = getAction(instructionSearchPlugin, "Search Instruction Patterns"); - performAction(openSearchDialogAction, true); + performAction(openSearchDialogAction, codeViewer, true); waitForSwing(); Component previewTable = @@ -137,7 +143,7 @@ public class InstructionPatternSearchScreenShots extends AbstractSearchScreenSho DockingActionIf openSearchDialogAction = getAction(instructionSearchPlugin, "Search Instruction Patterns"); - performAction(openSearchDialogAction, true); + performAction(openSearchDialogAction, codeViewer, true); waitForSwing(); Component controlPanel = @@ -158,7 +164,7 @@ public class InstructionPatternSearchScreenShots extends AbstractSearchScreenSho DockingActionIf openSearchDialogAction = getAction(instructionSearchPlugin, "Search Instruction Patterns"); - performAction(openSearchDialogAction, true); + performAction(openSearchDialogAction, codeViewer, true); waitForSwing(); Component instructionTable = @@ -180,7 +186,7 @@ public class InstructionPatternSearchScreenShots extends AbstractSearchScreenSho DockingActionIf openSearchDialogAction = getAction(instructionSearchPlugin, "Search Instruction Patterns"); - performAction(openSearchDialogAction, true); + performAction(openSearchDialogAction, codeViewer, true); waitForSwing(); Component previewTable = @@ -205,7 +211,7 @@ public class InstructionPatternSearchScreenShots extends AbstractSearchScreenSho DockingActionIf openSearchDialogAction = getAction(instructionSearchPlugin, "Search Instruction Patterns"); - performAction(openSearchDialogAction, true); + performAction(openSearchDialogAction, codeViewer, true); waitForSwing(); DialogComponentProvider dialog = getDialog();