Skip to content

Commit 06d5ce2

Browse files
committed
Add macros support
Signed-off-by: Cervenka Dusan <[email protected]>
1 parent 2fbcb1c commit 06d5ce2

File tree

1 file changed

+93
-13
lines changed

1 file changed

+93
-13
lines changed

dissect/cstruct/cstruct.py

Lines changed: 93 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -312,23 +312,23 @@ def values(self):
312312
def items(self):
313313
return self.typedefs.items()
314314

315-
def getEnumTypes(self):
316-
retVal: list[EnumType] = []
315+
def getTypes(self, classType):
316+
retVal: list[classType] = []
317317
allTypes = self.typedefs
318318
for currentType in allTypes.values():
319-
if isinstance(currentType, EnumType):
319+
if isinstance(currentType, classType):
320320
retVal.append(currentType)
321321

322322
return retVal
323323

324+
def getEnumTypes(self):
325+
return self.getTypes(EnumType)
326+
324327
def getStructTypes(self):
325-
retVal: list[StructureType] = []
326-
allTypes = self.typedefs
327-
for currentType in allTypes.values():
328-
if isinstance(currentType, StructureType):
329-
retVal.append(currentType)
328+
return self.getTypes(StructureType)
330329

331-
return retVal
330+
def getMacroTypes(self):
331+
return self.getTypes(MacroType)
332332

333333

334334
class Parser(object):
@@ -360,10 +360,14 @@ class CStyleParser(Parser):
360360

361361
def __init__(self, cstruct, compiled=True):
362362
self.compiled = compiled
363+
self.clearVersionDetails()
363364
super(CStyleParser, self).__init__(cstruct)
364365

365-
# TODO: Implement proper parsing
366+
def clearVersionDetails(self):
367+
self.structVersionDetails = {"name":"", "valB":2**16-1, "valL":0}
368+
366369
def parse(self, data):
370+
self._macros(data)
367371
self._constants(data)
368372
self._enums(data)
369373
self._structs(data)
@@ -467,13 +471,68 @@ def _structs(self, data):
467471
self.cstruct.addtype(td, st)
468472

469473
def _parse_fields_struct(self, s):
474+
def getNumber(sign:str, number:int):
475+
retVal = number
476+
direction = "="
477+
478+
if "<" in sign:
479+
direction = "<"
480+
if "=" not in sign:
481+
retVal -= 1
482+
elif ">" in sign:
483+
direction = ">"
484+
if "=" not in sign:
485+
retVal += 1
486+
elif "=" in sign:
487+
pass
488+
else:
489+
retVal = None
490+
direction = None
491+
492+
return retVal,direction
493+
494+
regex = r'(?P<if>#if\s*(?P<macroNameA>\w+)\s*(?P<signA>[<>=]*?)\s*(?P<valueA>[0-9]+)\s*(?:and\s*(?P<macroNameB>\w+)\s*(?P<signB>[<>=]*?)\s*(?P<valueB>[0-9]+))?)?\s*'+COMMENT_REGEX_START+r'(?P<type>[^\s]+)\s+(?P<name>[^\s\[:]+)(\s*:\s*(?P<bits>\d+))?(\[(?P<count>[^;\n]*)\])?;'+COMMENT_REGEX_END+r'(?P<endif>\s*#endif.*)?'
470495
fields = re.finditer(
471-
COMMENT_REGEX_START+r'(?P<type>[^\s]+)\s+(?P<name>[^\s\[:]+)(\s*:\s*(?P<bits>\d+))?(\[(?P<count>[^;\n]*)\])?;'+COMMENT_REGEX_END,
496+
regex,
472497
s, re.MULTILINE
473498
)
474499
r:list[StructureFieldType] = []
500+
475501
for f in fields:
476502
d = f.groupdict()
503+
# print(regex)
504+
# print(d)
505+
if d.get("if",None) != None:
506+
macroNameA = d.get('macroNameA',None)
507+
signA = d.get('signA',None)
508+
valueA = d.get('valueA',None)
509+
macroNameB = d.get('macroNameB', None)
510+
signB = d.get('signB',None)
511+
valueB = d.get('valueB', None)
512+
if macroNameB != None and macroNameB != macroNameA:
513+
raise Exception(f"Expected macroNameA==macroNameB got {macroNameA}!={macroNameB}")
514+
self.structVersionDetails["name"] = macroNameA
515+
numA,dirA = getNumber(signA, valueA)
516+
if dirA == "=":
517+
self.structVersionDetails["valL"] = valueA
518+
self.structVersionDetails["valB"] = valueA
519+
else:
520+
if dirA == "<":
521+
self.structVersionDetails["valB"] = numA
522+
elif dirA == ">":
523+
self.structVersionDetails["valL"] = numA
524+
if signB != None:
525+
numB,dirB = getNumber(signB, valueB)
526+
if dirA == dirB:
527+
raise Exception(f"Expected dirA different sign <> than dirB got {dirA}=={dirB}")
528+
if dirB == "<":
529+
self.structVersionDetails["valB"] = numB
530+
elif dirB == ">":
531+
self.structVersionDetails["valL"] = numB
532+
continue
533+
if d.get("endif",None) != None:
534+
self.clearVersionDetails()
535+
continue
477536
if d['type'].startswith('//'):
478537
continue
479538

@@ -501,7 +560,7 @@ def _parse_fields_struct(self, s):
501560
d['name'] = d['name'][1:]
502561
type_ = Pointer(self.cstruct, type_)
503562

504-
field = StructureFieldType(d['name'], type_, int(d['bits']) if d['bits'] else None, commentAttributes=commentAttributes)
563+
field = StructureFieldType(d['name'], type_, int(d['bits']) if d['bits'] else None, commentAttributes=commentAttributes, versionDetails=self.structVersionDetails.copy())
505564
r.append(field)
506565

507566
return r
@@ -527,6 +586,19 @@ def parse_comment_block(self,s):
527586

528587
return commentAttributes
529588

589+
def _macros(self, s):
590+
r = re.finditer(
591+
COMMENT_REGEX_START+r'#define\s*(?P<name>[A-Za-z0-9_]+)\s+(?P<value>[A-Za-z0-9_"()])'+COMMENT_REGEX_END,
592+
s, re.MULTILINE
593+
)
594+
595+
for t in r:
596+
d = t.groupdict()
597+
598+
mt = MacroType(self.cstruct, d["name"], d["value"])
599+
600+
self.cstruct.addtype(d['name'], mt, True)
601+
530602
def _lookups(self, data):
531603
r = re.finditer(r'\$(?P<name>[^\s]+) = ({[^}]+})\w*\n', data)
532604

@@ -1081,12 +1153,13 @@ def reset(self):
10811153
class StructureFieldType(object):
10821154
"""Holds a structure field."""
10831155

1084-
def __init__(self, name:str, type_:typeAll, bits=None, offset:typing.Union[int,None]=None, commentAttributes:typeCommentAttributes={}):
1156+
def __init__(self, name:str, type_:typeAll, bits=None, offset:typing.Union[int,None]=None, commentAttributes:typeCommentAttributes={}, versionDetails={}):
10851157
self.name:str = name
10861158
self.type:typeAll = type_
10871159
self.bits = bits
10881160
self.offset:typing.Union[int,None] = offset
10891161
self.commentAttributes:typeCommentAttributes = commentAttributes
1162+
self.versionDetails = versionDetails
10901163

10911164
def __repr__(self):
10921165
return '<Field {} {} {}>'.format(self.name, self.type, self.commentAttributes)
@@ -1466,6 +1539,13 @@ def __repr__(self):
14661539
return '<EnumType {}>'.format(self.name)
14671540

14681541

1542+
class MacroType(RawType):
1543+
def __init__(self, cstruct, name:str, value:typing.Any):
1544+
self.name = name
1545+
self.value = value
1546+
super(MacroType, self).__init__(cstruct, name, 0)
1547+
1548+
14691549
class EnumInstance(object):
14701550
"""Implements a value instance of an EnumType"""
14711551

0 commit comments

Comments
 (0)