]>
git.proxmox.com Git - mirror_frr.git/blob - python/tiabwarfo.py
1 # SPDX-License-Identifier: GPL-2.0-or-later
2 # FRR DWARF structure definition extractor
4 # Copyright (C) 2020 David Lamparter for NetDEF, Inc.
17 "xref_install_element",
24 def extract(filename
="lib/.libs/libfrr.so"):
26 Convert output from "pahole" to JSON.
28 Example pahole output:
29 $ pahole -C xref lib/.libs/libfrr.so
31 struct xrefdata * xrefdata; /* 0 8 */
32 enum xref_type type; /* 8 4 */
34 const char * file; /* 16 8 */
35 const char * func; /* 24 8 */
37 /* size: 32, cachelines: 1, members: 5 */
38 /* last cacheline: 32 bytes */
41 pahole
= subprocess
.check_output(
42 ["pahole", "-C", ",".join(structs
), filename
]
45 struct_re
= re
.compile(r
"^struct ([^ ]+) \{([^\}]+)};", flags
=re
.M | re
.S
)
46 field_re
= re
.compile(
47 r
"^\s*(?P<type>[^;\(]+)\s+(?P<name>[^;\[\]]+)(?:\[(?P<array>\d+)\])?;\s*\/\*(?P<comment>.*)\*\/\s*$"
49 comment_re
= re
.compile(r
"^\s*\/\*.*\*\/\s*$")
51 pastructs
= struct_re
.findall(pahole
)
54 for sname
, data
in pastructs
:
55 this
= out
.setdefault(sname
, {})
56 fields
= this
.setdefault("fields", [])
58 lines
= data
.strip().splitlines()
63 if line
.strip() == "":
65 m
= comment_re
.match(line
)
69 m
= field_re
.match(line
)
71 offs
, size
= m
.group("comment").strip().split()
74 typ_
= m
.group("type").strip()
75 name
= m
.group("name")
77 if name
.startswith("(*"):
80 name
= name
[2:].split(")")[0]
89 data
["array"] = int(m
.group("array"))
94 "%d padding bytes before struct %s.%s"
95 % (offs
- next_offs
, sname
, name
)
97 next_offs
= offs
+ size
100 raise ValueError("cannot process line: %s" % line
)
105 class FieldApplicator(object):
107 Fill ELFDissectStruct fields list from pahole/JSON
109 Uses the JSON file created by the above code to fill in the struct fields
110 in subclasses of ELFDissectStruct.
113 # only what we really need. add more as needed.
122 def __init__(self
, data
):
128 self
.classes
.append(cls
)
129 self
.clsmap
[cls
.struct
] = cls
131 def resolve(self
, cls
):
135 fieldrename
= getattr(cls
, "fieldrename", {})
138 return (fieldrename
.get(n
, n
),)
140 for field
in self
.data
[cls
.struct
]["fields"]:
141 typs
= field
["type"].split()
142 typs
= [i
for i
in typs
if i
not in ["const"]]
144 # this will break reuse of xrefstructs.json across 32bit & 64bit
147 # if field['offset'] != offset:
148 # assert offset < field['offset']
149 # out.append(('_pad', '%ds' % (field['offset'] - offset,)))
151 # pretty hacky C types handling, but covers what we need
154 while typs
[-1] == "*":
159 packtype
= ("P", None)
161 if typs
[0] == "char":
162 packtype
= ("P", str)
163 elif typs
[0] == "struct" and typs
[1] in self
.clsmap
:
164 packtype
= ("P", self
.clsmap
[typs
[1]])
165 elif typs
[0] == "enum":
167 elif typs
[0] in self
.packtypes
:
168 packtype
= (self
.packtypes
[typs
[0]],)
169 elif typs
[0] == "struct":
170 if typs
[1] in self
.clsmap
:
171 packtype
= (self
.clsmap
[typs
[1]],)
174 "embedded struct %s not in extracted data" % (typs
[1],)
178 "cannot decode field %s in struct %s (%s)"
179 % (cls
.struct
, field
["name"], field
["type"])
182 if "array" in field
and typs
[0] == "char":
183 packtype
= ("%ds" % field
["array"],)
184 out
.append(mkname(field
["name"]) + packtype
)
185 elif "array" in field
:
186 for i
in range(0, field
["array"]):
187 out
.append(mkname("%s_%d" % (field
["name"], i
)) + packtype
)
189 out
.append(mkname(field
["name"]) + packtype
)
191 # offset = field['offset'] + field['size']
196 for cls
in self
.classes
:
201 argp
= argparse
.ArgumentParser(description
="FRR DWARF structure extractor")
206 help="write JSON output",
207 default
="python/xrefstructs.json",
213 help="ELF file to read",
214 default
="lib/.libs/libfrr.so",
216 args
= argp
.parse_args()
218 out
= extract(args
.input)
219 with
open(args
.output
+ ".tmp", "w") as fd
:
220 json
.dump(out
, fd
, indent
=2, sort_keys
=True)
221 os
.rename(args
.output
+ ".tmp", args
.output
)
224 if __name__
== "__main__":