Skip to content

Commit 4bccce0

Browse files
committed
add global memory map
1 parent 3574f21 commit 4bccce0

File tree

13 files changed

+556
-20
lines changed

13 files changed

+556
-20
lines changed

chb/app/AppAccess.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
from chb.app.Function import Function
6464
from chb.app.FunctionInfo import FunctionInfo
6565
from chb.app.FunctionsData import FunctionsData
66+
from chb.app.GlobalMemoryMap import GlobalMemoryMap
6667
from chb.app.JumpTables import JumpTables
6768
from chb.app.SystemInfo import SystemInfo
6869
from chb.app.StringXRefs import StringsXRefs
@@ -128,6 +129,7 @@ def __init__(
128129
self._bcfiles: Optional[BCFiles] = None
129130

130131
self._typeconstraints = TypeConstraintStore(self)
132+
self._globalmemorymap: Optional[GlobalMemoryMap] = None
131133
self._systeminfo: Optional[SystemInfo] = None
132134

133135
@property
@@ -190,6 +192,16 @@ def tcdictionary(self) -> TypeConstraintDictionary:
190192
self._tcdictionary = TypeConstraintDictionary(self, None)
191193
return self._tcdictionary
192194

195+
@property
196+
def globalmemorymap(self) -> GlobalMemoryMap:
197+
if self._globalmemorymap is None:
198+
if UF.has_global_locations_file(self.path, self.filename):
199+
x = UF.get_global_locations_xnode(self.path, self.filename)
200+
self._globalmemorymap = GlobalMemoryMap(self, x)
201+
else:
202+
self._globalmemorymap = GlobalMemoryMap(self, None)
203+
return self._globalmemorymap
204+
193205
@property
194206
def bdictionary(self) -> BDictionary:
195207
if self._bdictionary is None:

chb/app/Function.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
from chb.util.graphutil import coalesce_lists
8787

8888
if TYPE_CHECKING:
89+
from chb.app.AppAccess import AppAccess
8990
from chb.app.FnStackFrame import FnStackFrame
9091
from chb.bctypes.BCTyp import BCTyp
9192

@@ -129,6 +130,10 @@ def path(self) -> str:
129130
def filename(self) -> str:
130131
return self._filename
131132

133+
@property
134+
def app(self) -> "AppAccess":
135+
return self.ixd.app
136+
132137
@property
133138
def bd(self) -> BDictionary:
134139
return self._bd

chb/app/GlobalMemoryMap.py

Lines changed: 332 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,332 @@
1+
# ------------------------------------------------------------------------------
2+
# CodeHawk Binary Analyzer
3+
# Author: Henny Sipma
4+
# ------------------------------------------------------------------------------
5+
# The MIT License (MIT)
6+
#
7+
# Copyright (c) 2024 Aarno Labs LLC
8+
#
9+
# Permission is hereby granted, free of charge, to any person obtaining a copy
10+
# of this software and associated documentation files (the "Software"), to deal
11+
# in the Software without restriction, including without limitation the rights
12+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13+
# copies of the Software, and to permit persons to whom the Software is
14+
# furnished to do so, subject to the following conditions:
15+
#
16+
# The above copyright notice and this permission notice shall be included in all
17+
# copies or substantial portions of the Software.
18+
#
19+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25+
# SOFTWARE.
26+
# ------------------------------------------------------------------------------
27+
28+
import xml.etree.ElementTree as ET
29+
30+
from typing import Dict, List, Optional, Tuple, TYPE_CHECKING
31+
32+
from chb.util.loggingutil import chklogger
33+
34+
if TYPE_CHECKING:
35+
from chb.app.AppAccess import AppAccess
36+
from chb.app.Function import Function
37+
from chb.app.Instruction import Instruction
38+
from chb.bctypes.BCDictionary import BCDictionary
39+
from chb.bctypes.BCTyp import BCTyp
40+
41+
42+
class GlobalReference:
43+
44+
def __init__(self, grefaddr: str, mmap: "GlobalMemoryMap") -> None:
45+
self._mmap = mmap
46+
self._grefaddr = grefaddr
47+
48+
@property
49+
def mmap(self) -> "GlobalMemoryMap":
50+
return self._mmap
51+
52+
@property
53+
def app(self) -> "AppAccess":
54+
return self.mmap.app
55+
56+
@property
57+
def grefaddr(self) -> str:
58+
return self._grefaddr
59+
60+
def __str__(self) -> str:
61+
return "Ref: " + self.grefaddr
62+
63+
64+
class GlobalLoad(GlobalReference):
65+
66+
def __init__(
67+
self,
68+
grefaddr: str,
69+
mmap: "GlobalMemoryMap",
70+
xnode: ET.Element) -> None:
71+
GlobalReference.__init__(self, grefaddr, mmap)
72+
self._xnode = xnode
73+
74+
@property
75+
def gaddr(self) -> str:
76+
return self._xnode.get("a", self.grefaddr)
77+
78+
@property
79+
def instr(self) -> str:
80+
return self._xnode.get("i", "0x0")
81+
82+
@property
83+
def function(self) -> "Function":
84+
return self.app.function(self.faddr)
85+
86+
@property
87+
def faddr(self) -> str:
88+
return self._xnode.get("f", "0x0")
89+
90+
@property
91+
def size(self) -> int:
92+
return int(self._xnode.get("s", "0"))
93+
94+
def __str__(self) -> str:
95+
if self.grefaddr == self.gaddr:
96+
return "Load: " + str(self.size)
97+
else:
98+
offset = int(self.gaddr, 16) - int(self.grefaddr, 16)
99+
return "Load[" + str(offset) + "]: " + str(self.size)
100+
101+
102+
class GlobalStore(GlobalReference):
103+
104+
def __init__(
105+
self,
106+
grefaddr: str,
107+
mmap: "GlobalMemoryMap",
108+
xnode: ET.Element) -> None:
109+
GlobalReference.__init__(self, grefaddr, mmap)
110+
self._xnode = xnode
111+
112+
@property
113+
def gaddr(self) -> str:
114+
return self._xnode.get("a", self.grefaddr)
115+
116+
@property
117+
def instr(self) -> str:
118+
return self._xnode.get("i", "0x0")
119+
120+
@property
121+
def faddr(self) -> str:
122+
return self._xnode.get("f", "0x0")
123+
124+
@property
125+
def size(self) -> int:
126+
return int(self._xnode.get("s", "0"))
127+
128+
@property
129+
def value(self) -> Optional[int]:
130+
optval = self._xnode.get("v")
131+
if optval is not None:
132+
return int(optval)
133+
else:
134+
return None
135+
136+
def __str__(self) -> str:
137+
if self.grefaddr == self.gaddr:
138+
offset = ""
139+
else:
140+
offset = "[" + str(int(self.gaddr, 16) - int(self.grefaddr, 16)) + "]"
141+
if self.value is None:
142+
strvalue = ""
143+
else:
144+
strvalue = " (:= " + str(self.value) + ")"
145+
return "Store" + offset + ": " + str(self.size) + strvalue
146+
147+
148+
class GlobalAddressArgument(GlobalReference):
149+
150+
def __init__(
151+
self,
152+
grefaddr: str,
153+
mmap: "GlobalMemoryMap",
154+
xnode: ET.Element) -> None:
155+
GlobalReference.__init__(self, grefaddr, mmap)
156+
self._xnode = xnode
157+
158+
@property
159+
def gaddr(self) -> str:
160+
return self._xnode.get("a", self.grefaddr)
161+
162+
@property
163+
def iaddr(self) -> str:
164+
return self._xnode.get("i", "0x0")
165+
166+
@property
167+
def faddr(self) -> str:
168+
return self._xnode.get("f", "0x0")
169+
170+
@property
171+
def function(self) -> "Function":
172+
return self.app.function(self.faddr)
173+
174+
@property
175+
def instr(self) -> "Instruction":
176+
return self.function.instruction(self.iaddr)
177+
178+
@property
179+
def argindex(self) -> int:
180+
return int(self._xnode.get("aix", "-1"))
181+
182+
def __str__(self) -> str:
183+
if self.grefaddr == self.gaddr:
184+
offset = ""
185+
else:
186+
offset = "[" + str(int(self.gaddr, 16) - int(self.grefaddr, 16)) + "]"
187+
return "Argument" + offset + ": " + str(self.instr.annotation)
188+
189+
190+
class GlobalLocation:
191+
192+
def __init__(self, mmap: "GlobalMemoryMap", xnode: ET.Element) -> None:
193+
self._mmap = mmap
194+
self._xnode = xnode
195+
self._grefs: Optional[List[GlobalReference]] = None
196+
197+
@property
198+
def mmap(self) -> "GlobalMemoryMap":
199+
return self._mmap
200+
201+
@property
202+
def name(self) -> str:
203+
return self._xnode.get("name", "?")
204+
205+
@property
206+
def addr(self) -> str:
207+
return self._xnode.get("a", "0x0")
208+
209+
@property
210+
def gtype(self) -> Optional["BCTyp"]:
211+
tix = self._xnode.get("tix", None)
212+
if tix is not None:
213+
return self.mmap.bcdictionary.typ(int(tix))
214+
return None
215+
216+
@property
217+
def grefs(self) -> List[GlobalReference]:
218+
if self._grefs is None:
219+
self._grefs = []
220+
for xgref in self._xnode.findall("gref"):
221+
xt = xgref.get("t", "U")
222+
if xt == "L":
223+
gload = GlobalLoad(self.addr, self.mmap, xgref)
224+
self._grefs.append(gload)
225+
elif xt == "S":
226+
gstore = GlobalStore(self.addr, self.mmap, xgref)
227+
self._grefs.append(gstore)
228+
elif xt == "CA":
229+
garg = GlobalAddressArgument(self.addr, self.mmap, xgref)
230+
self._grefs.append(garg)
231+
else:
232+
chklogger.logger.error(
233+
"Global reference type not known: %s for address %s",
234+
xt, self.addr)
235+
return self._grefs
236+
237+
@property
238+
def size(self) -> Optional[int]:
239+
s = self._xnode.get("size", None)
240+
if s is not None:
241+
return int(s)
242+
else:
243+
return None
244+
245+
246+
class GlobalMemoryMap:
247+
248+
def __init__(self, app: "AppAccess", xnode: Optional[ET.Element]) -> None:
249+
self._app = app
250+
self._xnode = xnode
251+
self._locations: Optional[Dict[str, GlobalLocation]] = None
252+
self._undefinedlocs: Optional[Dict[str, List[GlobalReference]]] = None
253+
254+
@property
255+
def app(self) -> "AppAccess":
256+
return self._app
257+
258+
@property
259+
def bcdictionary(self) -> "BCDictionary":
260+
return self.app.bcdictionary
261+
262+
@property
263+
def deflocnode(self) -> Optional[ET.Element]:
264+
if self._xnode is not None:
265+
return self._xnode.find("locations")
266+
return None
267+
268+
@property
269+
def refaddrnode(self) -> Optional[ET.Element]:
270+
if self._xnode is not None:
271+
return self._xnode.find("no-locations")
272+
return None
273+
274+
@property
275+
def locations(self) -> Dict[str, GlobalLocation]:
276+
if self._locations is None:
277+
self._locations = {}
278+
if self.deflocnode is not None:
279+
for xgloc in self.deflocnode.findall("gloc"):
280+
addr = xgloc.get("a", "0x0")
281+
self._locations[addr] = GlobalLocation(self, xgloc)
282+
return self._locations
283+
284+
@property
285+
def undefined_locations(self) -> Dict[str, List[GlobalReference]]:
286+
if self._undefinedlocs is None:
287+
self._undefinedlocs = {}
288+
if self.refaddrnode is not None:
289+
for xundef in self.refaddrnode.findall("orphan-loc"):
290+
refaddr = xundef.get("a", "0x0")
291+
xlst: List[GlobalReference] = []
292+
for xgref in xundef.findall("gref"):
293+
xt = xgref.get("t", "U")
294+
if xt == "L":
295+
gload = GlobalLoad(refaddr, self, xgref)
296+
xlst.append(gload)
297+
elif xt == "S":
298+
gstore = GlobalStore(refaddr, self, xgref)
299+
xlst.append(gstore)
300+
elif xt == "CA":
301+
garg = GlobalAddressArgument(refaddr, self, xgref)
302+
xlst.append(garg)
303+
else:
304+
chklogger.logger.error(
305+
"Global reference type not known: %s for "
306+
+ "address %s",
307+
xt, refaddr)
308+
self._undefinedlocs[refaddr] = xlst
309+
return self._undefinedlocs
310+
311+
def get_location_by_name(self, name: str) -> Optional[GlobalLocation]:
312+
for gloc in self.locations.values():
313+
if gloc.name == name:
314+
return gloc
315+
else:
316+
return None
317+
318+
def get_location(self, addr: str) -> Optional[GlobalLocation]:
319+
if addr in self.locations:
320+
return self.locations[addr]
321+
else:
322+
return None
323+
324+
def coverage(self) -> Tuple[int, int]:
325+
loccoverage: int = 0
326+
loccount: int = 0
327+
for gloc in self.locations.values():
328+
size = gloc.size
329+
if size is not None:
330+
loccoverage += size
331+
loccount += 1
332+
return (loccount, loccoverage)

0 commit comments

Comments
 (0)