forked from BinaryAnalysisPlatform/bap
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbapdoc.ml
294 lines (238 loc) · 8.35 KB
/
bapdoc.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
(** Builds BAP Annotated Reference .
The program relies on argot.1.2-devel version, that is available
from <https://github.com/ivg/argot#1.2-devel>.
The code works only for 4.03, as ocamldoc is broken for older
versions of OCaml.
*)
open Core_kernel.Std
open Bap_plugins.Std
let libraries = [
"Core libraries", [
"bap", "Bap.Std", "BAP standard library";
"regular", "Regular.Std", "regular inductive types";
"monads", "Monads.Std", "a missing monads library";
"ogre", "Ogre", "a sexp-based NoSQL database";
"bap-future", "Bap_future.Std", "coinductive types";
"graphlib", "Graphlib.Std", "graph library";
"bap-taint", "Bap_taint.Std", "The Taint Analysis Framework";
"bap-primus", "Bap_primus.Std", "The Microexecution Framework";
"bare", "Bare", "Binary Analysis Rule Engine";
];
"Hardware Architectures",
[
"bap-arm", "ARM", "ARM architecture";
"bap-x86-cpu", "X86_cpu", "x86 family";
];
"Programming Languages",
[
"bap-api", "Bap_api", "interface for adding new languages";
"bap-abi", "Bap_abi", "interface for adding new ABI";
"bap-c", "Bap_c.Std", "support library for C language";
];
"Auxiliary libraries",
[
"bap-bml", "Bap_bml", "an extensible DSL for term transformation";
"bap-build", "Bap_build.Std", "BAP build system as an ocamlbuild plugin";
"bap-byteweight", "Bap_byteweight", "an interface to byteweight implementation";
"bap-demangle", "Bap_demangle.Std", "custom name demanglers";
"bap-dwarf", "Bap_dwarf.Std", "native DWARF parser";
"bap-ida", "Bap_ida.Std", "call IDA from OCaml";
"bap-llvm", "Bap_llvm.Std", "setup LLVM backend";
"bap-traces", "Bap_traces.Std", "loading execution traces";
"bap-strings", "Bap_strings.Std", "text and string processing utilities";
"text-tags", "Text_tags", "Use semantics tags to format your texts";
];
]
let std_libraries = [
"Bap"; "Core_kernel"; "Regular"; "Graphlib"; "Future"; "Monads";
"Bap_primus"
]
let frontends = [
"bap", "bap main frontend";
"bap-mc", "machine code playground";
"bap-byteweight", "create, obtain and evaluate byteweight signatures";
"bap-fsi-benchmark", "function start identification benchmark game";
]
let tools = [
"baptop", "run BAP interactively";
"bapbuild", "build BAP plugins";
"bap-server", "call to BAP via JSON RPC";
"bapbundle", "bundle BAP plugins";
]
let introduction = {|
{2 Introduction}
Binary Analysis Platform is a framework for writing program analysis
tools, that target binary files. The framework consists of a bunch
of libraries, plugins and frontends. The libraries provide code
reusability, plugins facilitate extensibility and frontends serve as
entry points.
The BAP Standard Library, also known just as bap library, is the core
component, around which the rest of the Platform is built. Start by
reading its manual. Frontends come with comprehensive manuals,
that can be accessed by using [--help] command line options, or via
the [man] command, if the manpath is configured correctly. Finally,
you can access a man page for a plugin using
[--<PLUGIN>-help] command line option of a frontend, e.g., [bap --map-terms-help].
The document is autogenerated from the library mli files, using our
[bapdoc] utility, that relies on the standard [ocamldoc] and enhanced html
generator [argot]. The reference part of the doc is optimized for using
from an IDE powered by [merlin]. Although it should be also readable
and searchable directly from the browser. The type manifest search is
capable of finding values by type signatures, by using fuzzy search
techniques and unification over different representation over
semantically same types. If you do not see the search frame to the
left, then {{:argot_index.html}click_here}.
|}
let packages =
List.concat_map ~f:(fun (_,ps) -> List.map ~f:(fun (p,_,_) -> p) ps) libraries
let is_interface file =
Filename.check_suffix file ".ml" || Filename.check_suffix file ".mli"
module Pkg = struct
let deps pkg =
pkg :: Findlib.package_ancestors ["byte"] pkg
let dir pkg = Findlib.package_directory pkg
let files pkg =
let dir = dir pkg in
Sys.readdir dir |> Array.to_list |>
List.filter ~f:is_interface |>
List.map ~f:(Filename.concat dir)
end
let mkdir path =
if not (Sys.file_exists path) then
Unix.mkdir path 0o770
let run cmd =
let res = Sys.command cmd in
if res <> 0 then
failwith ("Command: '" ^ cmd ^ "' failed")
let compile pkg =
let out = Filename.temp_file "bapdoc" ".mldoc" in
run @@ sprintf "ocamlfind ocamldoc -package %s -dump %s %s"
(String.concat ~sep:"," (Pkg.deps pkg)) out
(String.concat ~sep:" " (Pkg.files pkg));
out
let debap name =
try
if String.sub name 0 4 = "bap-"
then String.sub name 4 (String.length name - 4)
else name
with exn -> name
let enbap name =
try
if String.sub name 0 3 = "bap" then name else "bap-"^name
with _ -> "bap-"^name
let generate_redirection lib entry =
mkdir "man3";
let redirection = sprintf {|
<!doctype html>
<html>
<head>
<meta http-equiv="refresh" content="0; url='../%s.html'" />
</head>
<body></body>
</html> |} entry in
let name = sprintf "man3/%s.3.html" lib in
Out_channel.write_all name ~data:redirection
let render_entry (lib,entry,desc) =
printf "compiling %s\n%!" lib;
generate_redirection lib entry;
sprintf "- {{!%s}%s} - %s" entry (debap lib) desc
let render_section (name,entries) =
sprintf "{3 %s}\n%s" name
(String.concat ~sep:"\n" @@ List.map ~f:render_entry entries)
let library_index =
sprintf "\n{2 Libraries}\n%s"
(List.map ~f:render_section libraries |> String.concat ~sep:"\n\n")
type info = {
man : string -> string;
help : string -> string;
}
let program = {
man = ident;
help = sprintf "%s --help=groff"
}
let plugin = {
man = sprintf "bap-plugin-%s";
help = sprintf "bap --%s-help=groff";
}
let tool = {
man = ident;
help = fun _ -> "false"
}
let generate_manual {man; help} tool =
mkdir "man1";
match Sys.command @@ sprintf "%s >/dev/null" (help tool) with
| 0 ->
let output = sprintf "man1/%s.1.html" (man tool) in
run @@ sprintf "%s | man2html -r > %s" (help tool) output;
Some output
| n ->
eprintf "Warning: can't render manpage for %s\n" tool;
eprintf "Called as %S, got:\n" (help tool);
ignore(Sys.command @@ sprintf "%s >&2" (help tool));
eprintf "\n%!";
None
let render_entry (name,desc,manual) =
printf "compiling %s\n%!" name;
match manual with
| None -> sprintf "- [%s] - %s" name desc
| Some file -> sprintf "- {{:%s}%s} - %s" file name desc
let render_entries es =
List.map ~f:render_entry es |> String.concat ~sep:"\n"
let render t descs =
List.map descs ~f:(fun (name,desc) ->
name, desc, generate_manual t name) |>
render_entries
let frontends_index =
sprintf "\n\n{2 Frontends}\n%s" @@ render program frontends
let tools_index =
sprintf "\n\n{2 Tools}\n%s" @@ render tool tools
let by_plugin_name p1 p2 =
String.compare (Plugin.name p1) (Plugin.name p2)
let plugins =
Plugins.list () |> List.sort ~cmp:by_plugin_name |>
List.map ~f:(fun p ->
Plugin.name p, Plugin.desc p) |>
render plugin
let plugins_index =
sprintf "\n\n{2 Plugins}\n%s" plugins
let hides = String.concat ~sep:"," std_libraries
let argot = if Dynlink.is_native then "argot.cmxs" else "argot.cmo"
let render modules =
let intro,out = Filename.open_temp_file "intro" ".txt" in
output_string out introduction;
output_string out library_index;
output_string out frontends_index;
output_string out plugins_index;
output_string out tools_index;
Out_channel.close out;
let options = String.concat ~sep:" " [
"-charset UTF-8";
"-html";
"-colorize-code";
"-short-paths";
"-i"; Pkg.dir "argot";
"-g"; argot;
"-short-functors";
"-hide"; hides;
"-passopt -search-frame";
"-passopt -search";
"-passopt -full-text";
"-passopt -hide-undocumented-values";
"-intro"; intro;
"-t 'BAR: BAP Annotated Reference'"
] in
printf "Linking\n%!";
run @@ sprintf "ocamlfind ocamldoc %s %s"
options
(List.map ~f:(sprintf "-load %s") modules |> String.concat ~sep:" ");
Sys.remove intro
let cleanup = List.iter ~f:Sys.remove
let generate () =
let modules = packages |> List.map ~f:compile in
try
render modules;
cleanup modules;
with exn ->
cleanup modules;
raise exn
let () = generate ()