1
1
open Core_kernel
2
- open Regular.Std
2
+ open Bap_core_theory
3
3
open Bap.Std
4
- include Self ()
5
4
6
5
module Config = Bap_main.Extension. Configuration
7
6
@@ -14,14 +13,62 @@ type error = [
14
13
| `Sys_error of string
15
14
]
16
15
16
+
17
+ type 'a data = {
18
+ name : string ;
19
+ load : (bytes -> 'a );
20
+ save : ('a -> bytes );
21
+ }
22
+
17
23
exception Failed of error
18
24
19
25
let fail error = raise (Failed error)
20
- let zip_error entry err =
21
- fail (`Corrupted (sprintf " %s: %s" entry err))
22
-
23
- let entry ?(comp =" default" ) ~mode arch =
24
- Arch. to_string arch / comp / mode
26
+ let corrupted entry err = `Corrupted (sprintf " %s: %s" entry err)
27
+ let zip_error entry err = fail (corrupted entry err)
28
+
29
+ let compiler_name =
30
+ Option. value_map ~default: " default" ~f: Theory.Compiler. name
31
+
32
+ let matches_modulo_bits t name =
33
+ match Theory.Target. matching t name with
34
+ | None -> false
35
+ | Some t' -> Theory.Target. bits t = Theory.Target. bits t'
36
+
37
+ let matching_entry ?compiler target data {Zip. filename} =
38
+ match String. split filename ~on: '/' with
39
+ | [p1; p2; p3] ->
40
+ matches_modulo_bits target p1 &&
41
+ String. equal (compiler_name compiler) p2 &&
42
+ String. equal data.name p3
43
+ | _ -> fail (`Corrupted (" invalid entry name: " ^ filename))
44
+
45
+ let with_input file k =
46
+ let zip = Zip. open_in file in
47
+ protect ~finally: (fun () -> Zip. close_in zip) ~f: (fun () -> k zip)
48
+
49
+ let with_output file k =
50
+ let zip = Zip. open_out file in
51
+ protect ~finally: (fun () -> Zip. close_out zip) ~f: (fun () -> k zip)
52
+
53
+ let read_entry ?compiler target data file =
54
+ with_input file @@ fun zip ->
55
+ Zip. entries zip |>
56
+ List. find ~f: (matching_entry ?compiler target data) |> function
57
+ | None -> None
58
+ | Some entry ->
59
+ Some (data.load (Bytes. of_string (Zip. read_entry zip entry)))
60
+
61
+ let read_entries file =
62
+ if Fn. non Sys. file_exists file then []
63
+ else with_input file @@ fun zip ->
64
+ Zip. entries zip |>
65
+ List. map ~f: (fun entry ->
66
+ entry,Zip. read_entry zip entry)
67
+
68
+ let target_name = Fn. compose KB.Name. unqualified Theory.Target. name
69
+
70
+ let make_entry ?compiler target data =
71
+ target_name target / compiler_name compiler / data.name
25
72
26
73
let make_path root = root / " signatures" / " byteweight.zip"
27
74
@@ -31,14 +78,88 @@ let default_path = match Sys.getenv_opt "BAP_SIGFILE" with
31
78
| Some path -> path
32
79
| None -> make_path Config. datadir
33
80
34
- let paths = [default_path; system_path]
35
-
36
- let resolve_path user = match user with
81
+ let default_paths = [default_path; system_path]
82
+
83
+ let try_lookup ?(paths =[] ) ?compiler target data =
84
+ paths @ default_paths |> List. find_map ~f: (fun path ->
85
+ if Sys. file_exists path
86
+ then read_entry ?compiler target data path
87
+ else None )
88
+
89
+ let of_exn = function
90
+ | Sys_error msg -> Error (`Sys_error msg)
91
+ | Zip. Error (_ ,ent ,err ) -> Error (corrupted ent err)
92
+ | Failed er -> Error er
93
+ | other -> raise other
94
+
95
+ let lookup ?paths ?compiler target data =
96
+ match try_lookup ?paths ?compiler target data with
97
+ | exception exn -> of_exn exn
98
+ | None -> Error (`No_entry (target_name target))
99
+ | Some data -> Ok data
100
+
101
+
102
+ let update_or_fail ?compiler target data payload path =
103
+ let entries =
104
+ read_entries path |>
105
+ List. filter ~f: (fun (entry ,_ ) ->
106
+ not (matching_entry ?compiler target data entry)) in
107
+ with_output path @@ fun zip ->
108
+ let path = make_entry ?compiler target data in
109
+ let data = Bytes. unsafe_to_string (data.save payload) in
110
+ Zip. add_entry data zip path;
111
+ List. iter entries ~f: (fun ({Zip. filename; extra; comment; mtime} ,data ) ->
112
+ Zip. add_entry data zip filename
113
+ ~extra ~comment ~mtime )
114
+
115
+ let copy input output =
116
+ let len = 0x1000 in
117
+ let buf = Bytes. create len in
118
+ let rec loop () =
119
+ let read = In_channel. input input ~buf ~pos: 0 ~len in
120
+ Out_channel. output output ~buf ~pos: 0 ~len: read;
121
+ if read = len then loop () in
122
+ loop ()
123
+
124
+ let temporary_copy file =
125
+ let tmp,output = Caml.Filename. open_temp_file " byteweight" " copy" in
126
+ In_channel. with_file file ~f: (fun input -> copy input output);
127
+ Out_channel. close output;
128
+ tmp
129
+
130
+ let update ?compiler target data payload path =
131
+ let tmp = temporary_copy path in
132
+ try
133
+ update_or_fail ?compiler target data payload path;
134
+ Sys. rename tmp path;
135
+ Ok ()
136
+ with exn ->
137
+ Sys. remove tmp;
138
+ of_exn exn
139
+
140
+ module Data = struct
141
+ let registry = Hash_set. create (module String )
142
+
143
+ let declare ~load ~save name =
144
+ if Hash_set. mem registry name
145
+ then failwithf " The byteweight data type named %S is \
146
+ already registered, please pick another name"
147
+ name () ;
148
+ Hash_set. add registry name;
149
+ {load; save; name}
150
+ end
151
+
152
+ (* the old deprecated implementation *)
153
+
154
+ let resolve_path user =
155
+ let user = Option. value_map user ~f: List. return ~default: [] in
156
+ let paths = user @ default_paths in
157
+ match List. find paths ~f: Sys. file_exists with
158
+ | None -> fail `No_signatures
37
159
| Some path -> path
38
- | None ->
39
- match List. find paths ~f: Sys. file_exists with
40
- | Some path -> path
41
- | None -> fail `No_signatures
160
+
161
+ let entry ?(comp =" default" ) ~mode arch =
162
+ Arch. to_string arch / comp / mode
42
163
43
164
let load_exn ?comp ?path ~mode arch =
44
165
let path = resolve_path path in
@@ -48,7 +169,7 @@ let load_exn ?comp ?path ~mode arch =
48
169
let entry_path = entry ?comp ~mode arch in
49
170
let r = try
50
171
let entry = Zip. find_entry zip entry_path in
51
- Ok (Zip. read_entry zip entry |> Bytes. of_string )
172
+ Ok (Zip. read_entry zip entry |> Caml. Bytes.unsafe_of_string )
52
173
with Caml. Not_found -> fail (`No_entry entry_path)
53
174
| Zip. Error (_ ,ent ,err ) -> zip_error ent err in
54
175
Zip. close_in zip;
0 commit comments