]>
git.proxmox.com Git - mirror_frr.git/blob - python/tiabwarfo.py
1 # FRR DWARF structure definition extractor
3 # Copyright (C) 2020 David Lamparter for NetDEF, Inc.
5 # This program is free software; you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by the Free
7 # Software Foundation; either version 2 of the License, or (at your option)
10 # This program is distributed in the hope that it will be useful, but WITHOUT
11 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 # You should have received a copy of the GNU General Public License along
16 # with this program; see the file COPYING; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 "xref_install_element",
37 def extract(filename
="lib/.libs/libfrr.so"):
39 Convert output from "pahole" to JSON.
41 Example pahole output:
42 $ pahole -C xref lib/.libs/libfrr.so
44 struct xrefdata * xrefdata; /* 0 8 */
45 enum xref_type type; /* 8 4 */
47 const char * file; /* 16 8 */
48 const char * func; /* 24 8 */
50 /* size: 32, cachelines: 1, members: 5 */
51 /* last cacheline: 32 bytes */
54 pahole
= subprocess
.check_output(
55 ["pahole", "-C", ",".join(structs
), filename
]
58 struct_re
= re
.compile(r
"^struct ([^ ]+) \{([^\}]+)};", flags
=re
.M | re
.S
)
59 field_re
= re
.compile(
60 r
"^\s*(?P<type>[^;\(]+)\s+(?P<name>[^;\[\]]+)(?:\[(?P<array>\d+)\])?;\s*\/\*(?P<comment>.*)\*\/\s*$"
62 comment_re
= re
.compile(r
"^\s*\/\*.*\*\/\s*$")
64 pastructs
= struct_re
.findall(pahole
)
67 for sname
, data
in pastructs
:
68 this
= out
.setdefault(sname
, {})
69 fields
= this
.setdefault("fields", [])
71 lines
= data
.strip().splitlines()
76 if line
.strip() == "":
78 m
= comment_re
.match(line
)
82 m
= field_re
.match(line
)
84 offs
, size
= m
.group("comment").strip().split()
87 typ_
= m
.group("type").strip()
88 name
= m
.group("name")
90 if name
.startswith("(*"):
93 name
= name
[2:].split(")")[0]
102 data
["array"] = int(m
.group("array"))
105 if offs
!= next_offs
:
107 "%d padding bytes before struct %s.%s"
108 % (offs
- next_offs
, sname
, name
)
110 next_offs
= offs
+ size
113 raise ValueError("cannot process line: %s" % line
)
118 class FieldApplicator(object):
120 Fill ELFDissectStruct fields list from pahole/JSON
122 Uses the JSON file created by the above code to fill in the struct fields
123 in subclasses of ELFDissectStruct.
126 # only what we really need. add more as needed.
135 def __init__(self
, data
):
141 self
.classes
.append(cls
)
142 self
.clsmap
[cls
.struct
] = cls
144 def resolve(self
, cls
):
148 fieldrename
= getattr(cls
, "fieldrename", {})
151 return (fieldrename
.get(n
, n
),)
153 for field
in self
.data
[cls
.struct
]["fields"]:
154 typs
= field
["type"].split()
155 typs
= [i
for i
in typs
if i
not in ["const"]]
157 # this will break reuse of xrefstructs.json across 32bit & 64bit
160 # if field['offset'] != offset:
161 # assert offset < field['offset']
162 # out.append(('_pad', '%ds' % (field['offset'] - offset,)))
164 # pretty hacky C types handling, but covers what we need
167 while typs
[-1] == "*":
172 packtype
= ("P", None)
174 if typs
[0] == "char":
175 packtype
= ("P", str)
176 elif typs
[0] == "struct" and typs
[1] in self
.clsmap
:
177 packtype
= ("P", self
.clsmap
[typs
[1]])
178 elif typs
[0] == "enum":
180 elif typs
[0] in self
.packtypes
:
181 packtype
= (self
.packtypes
[typs
[0]],)
182 elif typs
[0] == "struct":
183 if typs
[1] in self
.clsmap
:
184 packtype
= (self
.clsmap
[typs
[1]],)
187 "embedded struct %s not in extracted data" % (typs
[1],)
191 "cannot decode field %s in struct %s (%s)"
192 % (cls
.struct
, field
["name"], field
["type"])
195 if "array" in field
and typs
[0] == "char":
196 packtype
= ("%ds" % field
["array"],)
197 out
.append(mkname(field
["name"]) + packtype
)
198 elif "array" in field
:
199 for i
in range(0, field
["array"]):
200 out
.append(mkname("%s_%d" % (field
["name"], i
)) + packtype
)
202 out
.append(mkname(field
["name"]) + packtype
)
204 # offset = field['offset'] + field['size']
209 for cls
in self
.classes
:
214 argp
= argparse
.ArgumentParser(description
="FRR DWARF structure extractor")
219 help="write JSON output",
220 default
="python/xrefstructs.json",
226 help="ELF file to read",
227 default
="lib/.libs/libfrr.so",
229 args
= argp
.parse_args()
231 out
= extract(args
.input)
232 with
open(args
.output
+ ".tmp", "w") as fd
:
233 json
.dump(out
, fd
, indent
=2, sort_keys
=True)
234 os
.rename(args
.output
+ ".tmp", args
.output
)
237 if __name__
== "__main__":