diff options
author | Luke T. Shumaker <lukeshu@lukeshu.com> | 2024-11-12 09:51:27 -0700 |
---|---|---|
committer | Luke T. Shumaker <lukeshu@lukeshu.com> | 2024-11-12 09:51:27 -0700 |
commit | f399364f1b16fbf99c82f1a845b4c3ca3f0e7464 (patch) | |
tree | 7f6b42c25a1c34eb5b4e9e0170d1262ee74273ac | |
parent | 25930f0607fb8d16ad66203c919dd26133cd0702 (diff) |
Work on stack.c.gen
-rwxr-xr-x | build-aux/stack.c.gen | 52 | ||||
l--------- | libmisc/include/assert.h | 1 |
2 files changed, 44 insertions, 9 deletions
diff --git a/build-aux/stack.c.gen b/build-aux/stack.c.gen index 80bea85..ae05a78 100755 --- a/build-aux/stack.c.gen +++ b/build-aux/stack.c.gen @@ -96,8 +96,9 @@ def parse_vcg(reader: typing.TextIO) -> typing.Iterator[VCGElem]: class Node: - # from .title (`static` functions are prefixed with the - # compilation unit .c file, which is fine, we'll just leave it). + # from .title (`static` and `__weak` functions are prefixed with + # the compilation unit .c file. For static functions that's fine, + # but we'll have to handle it specially for __weak.). funcname: str # .label is "{funcname}\n{location}\n{nstatic} bytes (static}\n{ndynamic} dynamic objects" location: str @@ -108,16 +109,33 @@ class Node: calls: set[str] +re_location = re.compile(r"(?P<filename>.+):(?P<row>[0-9]+):(?P<col>[0-9]+)") + + +def read_source(location: str) -> str: + m = re_location.fullmatch(location) + if not m: + raise ValueError(f"unexpected label value {repr(location)}") + filename = m.group("filename") + row = int(m.group("row")) - 1 + col = int(m.group("col")) - 1 + with open(m.group("filename"), "r") as fh: + return fh.readlines()[row][col:].rstrip() + + def main(ci_fnames: list[str]) -> None: - re_label = re.compile( + re_node_label = re.compile( r"(?P<funcname>[^\n]+)\n" + r"(?P<location>[^\n]+:[0-9]+:[0-9]+)\n" + r"(?P<nstatic>[0-9]+) bytes \(static\)\n" + r"(?P<ndynamic>[0-9]+) dynamic objects", flags=re.MULTILINE, ) + re_call_vcall = re.compile(r"VCALL\((?P<obj>[^,]+), (?P<meth>[^,)]+)[,)].*") + re_call_other = re.compile(r"(?P<func>[^(]+)\(.*") graph: dict[str, Node] = dict() + qualified: dict[str, set[str]] = dict() def handle_elem(elem: VCGElem) -> None: match elem.typ: @@ -131,7 +149,7 @@ def main(ci_fnames: list[str]) -> None: node.funcname = v case "label": if elem.attrs.get("shape", "") != "ellipse": - m = re_label.fullmatch(v) + m = re_node_label.fullmatch(v) if not m: raise ValueError( f"unexpected label value {repr(v)}" @@ -149,6 +167,11 @@ def main(ci_fnames: list[str]) -> None: if node.funcname in graph: raise ValueError(f"duplicate node {repr(node.funcname)}") graph[node.funcname] = node + if ":" in node.funcname: + _, shortname = node.funcname.rsplit(":", 1) + if shortname not in qualified: + qualified[shortname] = set() + qualified[shortname].add(node.funcname) case "edge": caller: str | None = None callee: str | None = None @@ -166,6 +189,12 @@ def main(ci_fnames: list[str]) -> None: raise ValueError(f"incomplete edge: {repr(elem.attrs)}") if caller not in graph: raise ValueError(f"unknown caller: {caller}") + if callee == "__indirect_call": + callstr = read_source(elem.attrs.get("label", "")) + if m := re_call_vcall.fullmatch(callstr): + callee += f":{m.group('obj')}->vtable->{m.group('meth')}" + elif m := re_call_other.fullmatch(callstr): + callee += f":{m.group('func')}" graph[caller].calls.add(callee) case _: raise ValueError(f"unknown elem type {repr(elem.typ)}") @@ -183,7 +212,11 @@ def main(ci_fnames: list[str]) -> None: def nstatic(funcname: str, chain: list[str] = []) -> int: if funcname not in graph: if f"__wrap_{funcname}" in graph: + # Handle `ld --wrap` functions funcname = f"__wrap_{funcname}" + elif funcname in qualified and len(qualified[funcname]) == 1: + # Handle `__weak` functions + funcname = sorted(qualified[funcname])[0] else: missing.add(funcname) return 0 @@ -196,18 +229,19 @@ def main(ci_fnames: list[str]) -> None: ) namelen = max(len(name) for name in graph if name.endswith("_cr")) - print(("=" * namelen) + " =======") + numlen = max(len(str(nstatic(name))) for name in graph if name.endswith("_cr")) + print(("=" * namelen) + " " + "=" * numlen) for funcname in graph: if funcname.endswith("_cr"): - print(f"{funcname.ljust(namelen)} {nstatic(funcname)}") + print(f"{funcname.ljust(namelen)} {str(nstatic(funcname)).rjust(numlen)}") - print(("=" * namelen) + " =======") + print(("=" * namelen) + " " + "=" * numlen) for funcname in sorted(missing): - print(f"{funcname}\tmissing") + print(f"warning: missing: {funcname}") for cycle in sorted(cycles): - print(f"cycle: {cycle}") + print(f"warning: cycle: {cycle}") print("*/") diff --git a/libmisc/include/assert.h b/libmisc/include/assert.h new file mode 120000 index 0000000..8473e36 --- /dev/null +++ b/libmisc/include/assert.h @@ -0,0 +1 @@ +libmisc/assert.h
\ No newline at end of file |