Source file owee_elf_notes.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
module Read = Owee_buf.Read
let padding n = (4 - (n land 3)) land 3
let gulp_padding cursor size =
let unread = padding size in
if unread > 0 then begin
Owee_buf.ensure cursor unread "Not found padding after note name";
Owee_buf.advance cursor unread
end
let check_string_length size str =
let len = String.length str + 1 in
if not (len = size) then
Owee_buf.invalid_format
(Printf.sprintf "Unexpected length of %s instead of %d\n" str size)
let read_desc_size cursor ~expected_owner ~expected_type =
Owee_buf.ensure cursor (4 * 3) "Note header truncated";
let namesz = Read.u32 cursor in
check_string_length namesz expected_owner;
let descsz = Read.u32 cursor in
let typ = Read.u32 cursor in
if not (typ = expected_type) then
Owee_buf.invalid_format
(Printf.sprintf "Unexpected note type %d instead of %d\n"
typ expected_type);
Owee_buf.ensure cursor namesz "Note owner name truncated";
(match Read.zero_string cursor ~maxlen:namesz () with
| None ->
Owee_buf.invalid_format
(Printf.sprintf "Cannot read note owner of length %d\n" namesz)
| Some owner ->
if not (String.equal owner expected_owner) then
Owee_buf.invalid_format
(Printf.sprintf "Unexpected note owner %s instead of %s\n"
owner expected_owner));
gulp_padding cursor namesz;
Owee_buf.ensure cursor descsz
(Printf.sprintf "Cannot read note description of size %d\n" descsz);
descsz
let cursor =
Owee_buf.ensure cursor (4 * 3) "Note header truncated";
let namesz = Read.u32 cursor in
let descsz = Read.u32 cursor in
let typ = Read.u32 cursor in
Owee_buf.ensure cursor namesz "Note owner name truncated";
let owner =
match Read.zero_string cursor ~maxlen:namesz () with
| None ->
Owee_buf.invalid_format
(Printf.sprintf "Cannot read owner of length %d\n" namesz)
| Some str ->
check_string_length namesz str;
str
in
gulp_padding cursor namesz;
Owee_buf.ensure cursor descsz
(Printf.sprintf "Cannot read note description of size %d\n" descsz);
{ owner;
size = descsz;
typ;
}
exception Section_not_found of string
let find_notes_section sections name =
match Owee_elf.find_section sections name with
| None -> raise (Section_not_found name)
| Some s ->
match s.sh_type with
| 7 -> s
| _ ->
Owee_buf.invalid_format
(Printf.sprintf "Unexpected type %d of %s section, instead of SHT_NOTE=7\n"
s.sh_type s.sh_name_str)
module Stapsdt = struct
type t =
{ addr : int64 (** address of the probe site *)
; semaphore : int64 option (** address of the semaphore corresponding to the probe *)
; provider : string
; name : string
; args : string (** probe arguments *)
}
let adjust addr ~actual_base ~recorded_base =
Int64.add (Int64.sub actual_base recorded_base) addr
let read cursor ~actual_base =
let descsz = read_desc_size
~expected_owner:"stapsdt"
~expected_type:3
cursor
in
if descsz < 8 * 3
then Owee_buf.invalid_format
(Printf.sprintf "Too small size of note %d\n" descsz);
let addr = Read.u64 cursor in
let recorded_base = Read.u64 cursor in
let semaphore =
let n = Read.u64 cursor in
if Int64.equal n 0L then None else Some n
in
let maxlen = descsz - (8 * 3) in
let provider =
match Read.zero_string cursor ~maxlen () with
| None -> Owee_buf.invalid_format "Cannot read probe provider"
| Some s -> s
in
let maxlen = maxlen - String.length provider - 1 in
let name =
match Read.zero_string cursor ~maxlen () with
| None -> Owee_buf.invalid_format "Cannot read probe name"
| Some s -> s
in
let maxlen = maxlen - String.length name - 1 in
let args =
match Read.zero_string cursor ~maxlen () with
| None -> Owee_buf.invalid_format "Cannot read probe's arguments"
| Some s -> s
in
gulp_padding cursor descsz;
{ addr = adjust addr ~actual_base ~recorded_base
; semaphore = begin match semaphore with
| None -> None
| Some s -> Some (adjust s ~actual_base ~recorded_base)
end
; provider
; name
; args
}
let iter map sections ~f =
let s = find_notes_section sections ".note.stapsdt" in
match Owee_elf.find_section sections ".stapsdt.base" with
| None ->
Owee_buf.invalid_format
(Printf.sprintf
"Found .note.stapsdt but not .stapsdt.base section\n")
| Some base_section ->
let body = Owee_elf.section_body map s in
let cursor = Owee_buf.cursor body in
while not (Owee_buf.at_end cursor) do
let note = read cursor ~actual_base:base_section.sh_addr in
f note
done
end
let char_hex n =
Char.unsafe_chr (n + if n < 10 then Char.code '0' else (Char.code 'a' - 10))
let hex_to_string cursor size =
let result = Bytes.create (size*2) in
for i = 0 to size - 1 do
let x = Read.u8 cursor in
Bytes.unsafe_set result (i*2) (char_hex (x lsr 4));
Bytes.unsafe_set result (i*2+1) (char_hex (x land 0x0f));
done;
Bytes.unsafe_to_string result
let read_buildid map sections =
let s = find_notes_section sections ".note.gnu.build-id" in
let body = Owee_elf.section_body map s in
let cursor = Owee_buf.cursor body in
let descsz = read_desc_size cursor
~expected_owner:"GNU"
~expected_type: 3 in
let buildid = hex_to_string cursor descsz in
gulp_padding cursor descsz;
if not (Owee_buf.at_end cursor) then
Owee_buf.invalid_format "Unexpected data after buildid";
buildid