33import logging
44import tempfile
55
6- from .binary_analyzer import BinaryAnalyzer
6+ from .binary_analyzer import BinaryAnalyzer , UnknownInstructionModeError
77
88logger = logging .getLogger (__name__ )
99
@@ -41,11 +41,10 @@ def __init__(self, binary_path: str, language: str | None = None, **kwargs):
4141 self .flatapi = FlatProgramAPI (self .currentProgram )
4242
4343 import ghidra
44+ import ghidra .program .model .block
4445
4546 self .ghidra = ghidra
46- self .bbm = self .ghidra .program .model .block .BasicBlockModel (
47- self .currentProgram
48- )
47+ self .bbm = ghidra .program .model .block .BasicBlockModel (self .currentProgram )
4948 except BaseException :
5049 self .shutdown ()
5150 raise
@@ -78,59 +77,70 @@ def shutdown(self):
7877 if temp_proj_dir_ctx is not None :
7978 temp_proj_dir_ctx .cleanup ()
8079
81- def normalize_addr (self , addr ):
82- addr = addr .getOffset ()
80+ @property
81+ def load_base (self ) -> int :
82+ return self .currentProgram .getImageBase ().getOffset ()
83+
84+ def normalize_addr (self , addr : int ) -> int :
8385 if self .currentProgram .getRelocationTable ().isRelocatable ():
84- addr -= self .currentProgram . getImageBase (). getOffset ()
86+ addr -= self .load_base
8587 return addr
8688
87- def denormalize_addr (self , addr ) :
89+ def denormalize_addr (self , addr : int ) -> int :
8890 if self .currentProgram .getRelocationTable ().isRelocatable ():
89- addr += self .currentProgram .getImageBase ().getOffset ()
90- return self .flatapi .toAddr (hex (addr ))
91+ addr += self .load_base
92+ return addr
93+
94+ def _normalize_ghidra_addr (self , addr ) -> int :
95+ return self .normalize_addr (addr .getOffset ())
96+
97+ def _to_ghidra_addr (self , addr : int ):
98+ return self .flatapi .toAddr (hex (self .denormalize_addr (addr )))
9199
92100 def mem_addr_to_file_offset (self , addr : int ) -> int :
93- addr = self .denormalize_addr (addr )
101+ ghidra_addr = self ._to_ghidra_addr (addr )
94102 try :
95103 return (
96104 self .currentProgram .getMemory ()
97- .getAddressSourceInfo (addr )
105+ .getAddressSourceInfo (ghidra_addr )
98106 .getFileOffset ()
99107 )
100108 except Exception : # noqa: BLE001
101109 raise ValueError ("Can't get file offset for addr" ) from None
102110
103111 def get_basic_block (self , addr : int ) -> dict [str , int | list [int ]]:
104- logger .info (f"getting basic block at 0x { addr } with ghidra" )
105- addr = self .denormalize_addr (addr )
112+ logger .info (f"getting basic block at { hex ( addr ) } with ghidra" )
113+ ghidra_addr = self ._to_ghidra_addr (addr )
106114
107115 block = self .bbm .getFirstCodeBlockContaining (
108- addr , self .ghidra .util .task .TaskMonitor .DUMMY
116+ ghidra_addr , self .ghidra .util .task .TaskMonitor .DUMMY
109117 )
110118 if block is None :
111- raise ValueError (f"Cannot find block containing address 0x { addr } " )
119+ raise ValueError (f"Cannot find block containing address { hex ( addr ) } " )
112120 instrs = []
113121 ii = self .currentProgram .getListing ().getInstructions (block , True )
114122 for i in ii :
115- instrs .append (self .normalize_addr (i .getAddress ()))
123+ instrs .append (self ._normalize_ghidra_addr (i .getAddress ()))
116124 return {
117- "start" : self .normalize_addr (block .getMinAddress ()),
118- "end" : self .normalize_addr (block .getMinAddress ()) + block .getNumAddresses (),
125+ "start" : self ._normalize_ghidra_addr (block .getMinAddress ()),
126+ "end" : self ._normalize_ghidra_addr (block .getMinAddress ())
127+ + block .getNumAddresses (),
119128 "size" : block .getNumAddresses (),
120129 "instruction_addrs" : instrs ,
121130 }
122131
123132 def get_instr_bytes_at (self , addr : int , num_instr = 1 ):
124- addr = self .denormalize_addr (addr )
125- instr = self .currentProgram .getListing ().getInstructionContaining (addr )
133+ ghidra_addr = self ._to_ghidra_addr (addr )
134+ instr = self .currentProgram .getListing ().getInstructionContaining (ghidra_addr )
126135 if instr is None :
127136 return None
128- b = instr .getBytes ()
137+ b = bytes ( instr .getBytes () )
129138 for _i in range (1 , num_instr ):
130139 instr = instr .getNext ()
131- b = b"" .join ([b , instr .getBytes ()])
140+ b = b"" .join ([b , bytes ( instr .getBytes () )])
132141 logger .info (
133- f"got instr bytes of length { len (b )} for { num_instr } instrs at 0x{ addr } with ghidra"
142+ f"got instr bytes of length { len (b )} for { num_instr } instrs at "
143+ f"{ hex (addr )} with ghidra"
134144 )
135145 return b
136146
@@ -143,7 +153,7 @@ def get_unused_funcs(self) -> list[dict[str, int]]:
143153 b = f .getBody ()
144154 unused_funcs .append (
145155 {
146- "addr" : self .normalize_addr (b .getMinAddress ()),
156+ "addr" : self ._normalize_ghidra_addr (b .getMinAddress ()),
147157 "size" : b .getNumAddresses (),
148158 }
149159 )
@@ -162,15 +172,16 @@ def get_all_symbols(self) -> dict[str, int]:
162172 for f in fi :
163173 if f .getName () in symbols :
164174 continue
165- symbols [f .getName ()] = self .normalize_addr (f .getEntryPoint ())
175+ symbols [f .getName ()] = self ._normalize_ghidra_addr (f .getEntryPoint ())
166176 if self .is_thumb (symbols [f .getName ()]):
167177 symbols [f .getName ()] += 1
168178 return symbols
169179
170180 def get_function (self , name_or_addr : int | str ) -> dict [str , int ] | None :
171181 if isinstance (name_or_addr , int ):
172- name_or_addr = self .denormalize_addr (name_or_addr )
173- func = self .currentProgram .getListing ().getFunctionContaining (name_or_addr )
182+ func = self .currentProgram .getListing ().getFunctionContaining (
183+ self ._to_ghidra_addr (name_or_addr )
184+ )
174185 if func is None :
175186 return None
176187 elif isinstance (name_or_addr , str ):
@@ -183,16 +194,33 @@ def get_function(self, name_or_addr: int | str) -> dict[str, int] | None:
183194
184195 b = func .getBody ()
185196 return {
186- "addr" : self .normalize_addr (b .getMinAddress ()),
197+ "addr" : self ._normalize_ghidra_addr (b .getMinAddress ()),
187198 "size" : b .getNumAddresses (),
188199 }
189200
190- def is_thumb (self , addr : int ) -> bool :
191- addr = self . denormalize_addr ( addr )
192- r = self .currentProgram .getRegister ("TMode" )
193- if r is None :
201+ def thumb_mode (self , addr : int ) -> bool | None :
202+ """Return the Ghidra ARM mode, or None when it is unknown."""
203+ register = self .currentProgram .getRegister ("TMode" )
204+ if register is None :
194205 return False
195- v = self .currentProgram .getProgramContext ().getRegisterValue (r , addr )
196- t = v .unsignedValueIgnoreMask .intValue () == 1
197- logger .info (f"address 0x{ addr } { 'is' if t else 'is not' } thumb from ghidra" )
198- return t
206+
207+ value = self .currentProgram .getProgramContext ().getRegisterValue (
208+ register , self ._to_ghidra_addr (addr )
209+ )
210+ if value is None or not value .hasValue ():
211+ logger .info (f"address { hex (addr )} has no TMode value in ghidra" )
212+ return None
213+
214+ is_thumb = value .unsignedValueIgnoreMask .intValue () == 1
215+ logger .info (
216+ f"address { hex (addr )} { 'is' if is_thumb else 'is not' } thumb from ghidra"
217+ )
218+ return is_thumb
219+
220+ def is_thumb (self , addr : int ) -> bool :
221+ mode = self .thumb_mode (addr )
222+ if mode is None :
223+ raise UnknownInstructionModeError (
224+ f"Cannot determine ARM instruction mode at { hex (addr )} "
225+ )
226+ return mode
0 commit comments