From 7c8afd26cf469fb9bfb6bb57eef62b4751f8074a Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Tue, 26 Nov 2024 15:12:34 -0600 Subject: [PATCH] scripts: Added alignment info to structs.py Dwarf-info doesn't actually provide alignment info with the current tools I'm using (but it does look like DW_AT_alignment was added in a recent version), so for now this is just a heuristic based on the largest base/pointer type. This heuristic is still useful info and probably correct for the types littlefs cares about (no SIMD here!). This is also another field that folds using max, so that's fun. --- scripts/structs.py | 51 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 9 deletions(-) diff --git a/scripts/structs.py b/scripts/structs.py index 4fa75a28..ae423a1e 100755 --- a/scripts/structs.py +++ b/scripts/structs.py @@ -128,22 +128,23 @@ class RInt(co.namedtuple('RInt', 'x')): # struct size results class StructResult(co.namedtuple('StructResult', [ 'file', 'struct', - 'size', + 'size', 'align', 'children'])): _by = ['file', 'struct'] - _fields = ['size'] - _sort = ['size'] - _types = {'size': RInt} + _fields = ['size', 'align'] + _sort = ['size', 'align'] + _types = {'size': RInt, 'align': RInt} __slots__ = () - def __new__(cls, file='', struct='', size=0, children=[]): + def __new__(cls, file='', struct='', size=0, align=0, children=[]): return super().__new__(cls, file, struct, - RInt(size), + RInt(size), RInt(align), children or []) def __add__(self, other): return StructResult(self.file, self.struct, self.size + other.size, + max(self.align, other.align), self.children + other.children) @@ -236,6 +237,14 @@ def collect_dwarf_info(obj_path, filter=None, *, def __contains__(self, k): return k in self.ats + def __repr__(self): + return '%s(%d, 0x%x, %r, %r)' % ( + self.__class__.__name__, + self.level, + self.off, + self.tag, + self.ats) + info_pattern = re.compile( '^\s*(?:<(?P[^>]*)>' '\s*<(?P[^>]*)>' @@ -357,6 +366,28 @@ def collect(obj_paths, *, assert False size = sizeof(entry) + # find alignment, recursing if necessary + # + # Dwarf doesn't seem to give us this info, so we infer it from + # the size of children pointer/base types. This is _usually_ + # correct. + def alignof(entry): + # pointer/base type? assume this size == alignment + if entry.tag in { + 'DW_TAG_pointer_type', + 'DW_TAG_base_type'}: + return int(entry['DW_AT_byte_size']) + # indirect type? + elif 'DW_AT_type' in entry: + type = int(entry['DW_AT_type'].strip('<>'), 0) + return alignof(info[type]) + # struct/union probably + elif entry.children: + return max(alignof(child) for child in entry.children) + else: + assert False + align = alignof(entry) + # find children, recursing if necessary def childrenof(entry): # pointer? these end up recursive but the underlying @@ -367,12 +398,14 @@ def collect(obj_paths, *, elif 'DW_AT_type' in entry: type = int(entry['DW_AT_type'].strip('<>'), 0) return childrenof(info[type]) + # struct/union probably else: children = [] for child in entry.children: name = child['DW_AT_name'].split(':')[-1].strip() size = sizeof(child) - children.append(StructResult(file, name, size, + align = alignof(child) + children.append(StructResult(file, name, size, align, childrenof(child))) return children children = childrenof(entry) @@ -380,10 +413,10 @@ def collect(obj_paths, *, # typdefs exist in a separate namespace, so we need to track # these separately if entry.tag == 'DW_TAG_typedef': - typedefs[no] = StructResult(file, name, size, children) + typedefs[no] = StructResult(file, name, size, align, children) typedefed.add(int(entry['DW_AT_type'].strip('<>'), 0)) else: - types[no] = StructResult(file, name, size, children) + types[no] = StructResult(file, name, size, align, children) # let typedefs take priority results.extend(typedefs.values())