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.
This commit is contained in:
Christopher Haster
2024-11-26 15:12:34 -06:00
parent 35f68a733c
commit 7c8afd26cf
+42 -9
View File
@@ -128,22 +128,23 @@ class RInt(co.namedtuple('RInt', 'x')):
# struct size results # struct size results
class StructResult(co.namedtuple('StructResult', [ class StructResult(co.namedtuple('StructResult', [
'file', 'struct', 'file', 'struct',
'size', 'size', 'align',
'children'])): 'children'])):
_by = ['file', 'struct'] _by = ['file', 'struct']
_fields = ['size'] _fields = ['size', 'align']
_sort = ['size'] _sort = ['size', 'align']
_types = {'size': RInt} _types = {'size': RInt, 'align': RInt}
__slots__ = () __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, return super().__new__(cls, file, struct,
RInt(size), RInt(size), RInt(align),
children or []) children or [])
def __add__(self, other): def __add__(self, other):
return StructResult(self.file, self.struct, return StructResult(self.file, self.struct,
self.size + other.size, self.size + other.size,
max(self.align, other.align),
self.children + other.children) self.children + other.children)
@@ -236,6 +237,14 @@ def collect_dwarf_info(obj_path, filter=None, *,
def __contains__(self, k): def __contains__(self, k):
return k in self.ats 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( info_pattern = re.compile(
'^\s*(?:<(?P<level>[^>]*)>' '^\s*(?:<(?P<level>[^>]*)>'
'\s*<(?P<off>[^>]*)>' '\s*<(?P<off>[^>]*)>'
@@ -357,6 +366,28 @@ def collect(obj_paths, *,
assert False assert False
size = sizeof(entry) 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 # find children, recursing if necessary
def childrenof(entry): def childrenof(entry):
# pointer? these end up recursive but the underlying # pointer? these end up recursive but the underlying
@@ -367,12 +398,14 @@ def collect(obj_paths, *,
elif 'DW_AT_type' in entry: elif 'DW_AT_type' in entry:
type = int(entry['DW_AT_type'].strip('<>'), 0) type = int(entry['DW_AT_type'].strip('<>'), 0)
return childrenof(info[type]) return childrenof(info[type])
# struct/union probably
else: else:
children = [] children = []
for child in entry.children: for child in entry.children:
name = child['DW_AT_name'].split(':')[-1].strip() name = child['DW_AT_name'].split(':')[-1].strip()
size = sizeof(child) size = sizeof(child)
children.append(StructResult(file, name, size, align = alignof(child)
children.append(StructResult(file, name, size, align,
childrenof(child))) childrenof(child)))
return children return children
children = childrenof(entry) children = childrenof(entry)
@@ -380,10 +413,10 @@ def collect(obj_paths, *,
# typdefs exist in a separate namespace, so we need to track # typdefs exist in a separate namespace, so we need to track
# these separately # these separately
if entry.tag == 'DW_TAG_typedef': 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)) typedefed.add(int(entry['DW_AT_type'].strip('<>'), 0))
else: else:
types[no] = StructResult(file, name, size, children) types[no] = StructResult(file, name, size, align, children)
# let typedefs take priority # let typedefs take priority
results.extend(typedefs.values()) results.extend(typedefs.values())