/src/libdwarf/fuzz/fuzz_findfuncbypc.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright 2021 Google LLC |
2 | | Licensed under the Apache License, Version 2.0 (the "License"); |
3 | | you may not use this file except in compliance with the License. |
4 | | You may obtain a copy of the License at |
5 | | http://www.apache.org/licenses/LICENSE-2.0 |
6 | | Unless required by applicable law or agreed to in writing, software |
7 | | distributed under the License is distributed on an "AS IS" BASIS, |
8 | | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
9 | | See the License for the specific language governing permissions and |
10 | | limitations under the License. |
11 | | */ |
12 | | // #include <config.h> |
13 | | #include <stdint.h> |
14 | | #include <stdio.h> |
15 | | #include <stdlib.h> |
16 | | #include <string.h> |
17 | | #include <sys/types.h> |
18 | | #include <unistd.h> |
19 | | |
20 | | /* |
21 | | * Libdwarf library callers can only use these headers. |
22 | | */ |
23 | | #include "dwarf.h" |
24 | | #include "libdwarf.h" |
25 | | |
26 | | #define DW_PR_DUx "llx" |
27 | | #define DW_PR_DSx "llx" |
28 | | #define DW_PR_DUu "llu" |
29 | | #define DW_PR_DSd "lld" |
30 | | |
31 | 73.6k | #define TRUE 1 |
32 | 405k | #define FALSE 0 |
33 | | static int unittype = DW_UT_compile; |
34 | | static Dwarf_Bool g_is_info = FALSE; |
35 | | |
36 | | int cu_version_stamp = 0; |
37 | | int cu_offset_size = 0; |
38 | | |
39 | | struct srcfilesdata { |
40 | | char **srcfiles; |
41 | | Dwarf_Signed srcfilescount; |
42 | | int srcfilesres; |
43 | | }; |
44 | | struct target_data_s { |
45 | | Dwarf_Debug td_dbg; |
46 | | Dwarf_Unsigned td_target_pc; /* from argv */ |
47 | | int td_print_details; /* from argv */ |
48 | | int td_reportallfound; /* from argv */ |
49 | | |
50 | | /* cu die data. */ |
51 | | Dwarf_Unsigned td_cu_lowpc; |
52 | | Dwarf_Unsigned td_cu_highpc; |
53 | | int td_cu_haslowhighpc; |
54 | | Dwarf_Die td_cu_die; |
55 | | char *td_cu_name; |
56 | | char *td_cu_comp_dir; |
57 | | Dwarf_Unsigned td_cu_number; |
58 | | struct srcfilesdata td_cu_srcfiles; |
59 | | Dwarf_Unsigned td_cu_ranges_base; |
60 | | |
61 | | Dwarf_Off td_ranges_offset; |
62 | | char *td_subprog_name; |
63 | | Dwarf_Unsigned td_subprog_fileindex; |
64 | | Dwarf_Die td_subprog_die; |
65 | | Dwarf_Unsigned td_subprog_lowpc; |
66 | | Dwarf_Unsigned td_subprog_highpc; |
67 | | int td_subprog_haslowhighpc; |
68 | | Dwarf_Unsigned td_subprog_lineaddr; |
69 | | Dwarf_Unsigned td_subprog_lineno; |
70 | | char *td_subprog_srcfile; /* dealloc */ |
71 | | }; |
72 | 11.8M | #define NOT_THIS_CU 10 |
73 | 421k | #define IN_THIS_CU 11 |
74 | 6.43M | #define FOUND_SUBPROG 12 |
75 | | |
76 | | static int look_for_our_target(Dwarf_Debug dbg, |
77 | | struct target_data_s *target_data, |
78 | | Dwarf_Error *errp); |
79 | | static int examine_die_data(Dwarf_Debug dbg, int is_info, Dwarf_Die die, |
80 | | int level, struct target_data_s *td, |
81 | | Dwarf_Error *errp); |
82 | | static int check_comp_dir(Dwarf_Debug dbg, Dwarf_Die die, |
83 | | struct target_data_s *td, Dwarf_Error *errp); |
84 | | static int get_die_and_siblings(Dwarf_Debug dbg, Dwarf_Die in_die, int is_info, |
85 | | int in_level, int cu_number, |
86 | | struct target_data_s *td, Dwarf_Error *errp); |
87 | | |
88 | | #if 0 |
89 | | DW_UT_compile 0x01 /* DWARF5 */ |
90 | | DW_UT_type 0x02 /* DWARF5 */ |
91 | | DW_UT_partial 0x03 /* DWARF5 */ |
92 | | #endif |
93 | | |
94 | 14.5k | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
95 | 14.5k | char filepath[256]; |
96 | 14.5k | sprintf(filepath, "/tmp/libfuzzer.%d", getpid()); |
97 | | |
98 | 14.5k | FILE *fp = fopen(filepath, "wb"); |
99 | 14.5k | if (!fp) { |
100 | 0 | return 0; |
101 | 0 | } |
102 | 14.5k | fwrite(data, size, 1, fp); |
103 | 14.5k | fclose(fp); |
104 | | |
105 | 14.5k | Dwarf_Debug dbg = 0; |
106 | 14.5k | Dwarf_Error error = 0; |
107 | 14.5k | Dwarf_Handler errhand = 0; |
108 | 14.5k | Dwarf_Ptr errarg = 0; |
109 | 14.5k | int i = 0; |
110 | 14.5k | Dwarf_Unsigned target_pc = 0x1000; |
111 | 14.5k | #define PATH_LEN 2000 |
112 | 14.5k | char real_path[PATH_LEN]; |
113 | 14.5k | struct target_data_s target_data; |
114 | | |
115 | | /* Added 19 May 2023 so valgrind will not complain |
116 | | about testing uninitialized values in |
117 | | check_coup_dir (for example). */ |
118 | 14.5k | memset(&target_data,0,sizeof(target_data)); |
119 | 14.5k | int res = |
120 | 14.5k | dwarf_init_path(filepath, 0, 0, DW_GROUPNUMBER_ANY, 0, 0, &dbg, &error); |
121 | 14.5k | if (res == DW_DLV_ERROR) { |
122 | 4.78k | dwarf_dealloc_error(dbg, error); |
123 | 4.78k | dwarf_finish(dbg); |
124 | 9.76k | } else { |
125 | 9.76k | res = look_for_our_target(dbg, &target_data, &error); |
126 | 9.76k | res = dwarf_finish(dbg); |
127 | 9.76k | } |
128 | | |
129 | 14.5k | unlink(filepath); |
130 | 14.5k | return 0; |
131 | 14.5k | } |
132 | | |
133 | | static int read_line_data(Dwarf_Debug dbg, struct target_data_s *td, |
134 | 1.30k | Dwarf_Error *errp) { |
135 | 1.30k | int res = 0; |
136 | 1.30k | Dwarf_Unsigned line_version = 0; |
137 | 1.30k | Dwarf_Small table_type = 0; |
138 | 1.30k | Dwarf_Line_Context line_context = 0; |
139 | 1.30k | Dwarf_Signed i = 0; |
140 | 1.30k | Dwarf_Signed baseindex = 0; |
141 | 1.30k | Dwarf_Signed endindex = 0; |
142 | 1.30k | Dwarf_Signed file_count = 0; |
143 | 1.30k | Dwarf_Unsigned dirindex = 0; |
144 | | |
145 | 1.30k | (void)dbg; |
146 | 1.30k | res = dwarf_srclines_b(td->td_cu_die, &line_version, &table_type, |
147 | 1.30k | &line_context, errp); |
148 | 1.30k | if (res != DW_DLV_OK) { |
149 | 977 | return res; |
150 | 977 | } |
151 | 323 | if (table_type == 0) { |
152 | 9 | int sres = 0; |
153 | | |
154 | 9 | sres = dwarf_srclines_files_indexes(line_context, &baseindex, &file_count, |
155 | 9 | &endindex, errp); |
156 | 9 | if (sres != DW_DLV_OK) { |
157 | 0 | dwarf_srclines_dealloc_b(line_context); |
158 | 0 | line_context = 0; |
159 | 0 | return sres; |
160 | 0 | } |
161 | 92 | for (i = baseindex; i < endindex; i++) { |
162 | 83 | Dwarf_Unsigned modtime = 0; |
163 | 83 | Dwarf_Unsigned flength = 0; |
164 | 83 | Dwarf_Form_Data16 *md5data = 0; |
165 | 83 | int vres = 0; |
166 | 83 | const char *name = 0; |
167 | | |
168 | 83 | vres = dwarf_srclines_files_data_b(line_context, i, &name, &dirindex, |
169 | 83 | &modtime, &flength, &md5data, errp); |
170 | 83 | if (vres != DW_DLV_OK) { |
171 | 0 | dwarf_srclines_dealloc_b(line_context); |
172 | 0 | line_context = 0; |
173 | 0 | return vres; |
174 | 0 | } |
175 | 83 | } |
176 | 9 | dwarf_srclines_dealloc_b(line_context); |
177 | 9 | return DW_DLV_OK; |
178 | 314 | } else if (table_type == 1) { |
179 | 313 | const char *dir_name = 0; |
180 | 313 | int sres = 0; |
181 | 313 | Dwarf_Line *linebuf = 0; |
182 | 313 | Dwarf_Signed linecount = 0; |
183 | 313 | Dwarf_Signed dir_count = 0; |
184 | 313 | Dwarf_Addr prev_lineaddr = 0; |
185 | 313 | Dwarf_Unsigned prev_lineno = 0; |
186 | 313 | char *prev_linesrcfile = 0; |
187 | | |
188 | 313 | sres = dwarf_srclines_files_indexes(line_context, &baseindex, &file_count, |
189 | 313 | &endindex, errp); |
190 | 313 | if (sres != DW_DLV_OK) { |
191 | 0 | dwarf_srclines_dealloc_b(line_context); |
192 | 0 | line_context = 0; |
193 | 0 | return sres; |
194 | 0 | } |
195 | 19.6k | for (i = baseindex; i < endindex; i++) { |
196 | 19.3k | Dwarf_Unsigned dirindexb = 0; |
197 | 19.3k | Dwarf_Unsigned modtime = 0; |
198 | 19.3k | Dwarf_Unsigned flength = 0; |
199 | 19.3k | Dwarf_Form_Data16 *md5data = 0; |
200 | 19.3k | int vres = 0; |
201 | 19.3k | const char *name = 0; |
202 | | |
203 | 19.3k | vres = dwarf_srclines_files_data_b(line_context, i, &name, &dirindexb, |
204 | 19.3k | &modtime, &flength, &md5data, errp); |
205 | 19.3k | if (vres != DW_DLV_OK) { |
206 | 0 | dwarf_srclines_dealloc_b(line_context); |
207 | 0 | line_context = 0; |
208 | 0 | return vres; |
209 | 0 | } |
210 | 19.3k | } |
211 | 313 | sres = dwarf_srclines_include_dir_count(line_context, &dir_count, errp); |
212 | 313 | if (sres != DW_DLV_OK) { |
213 | 0 | dwarf_srclines_dealloc_b(line_context); |
214 | 0 | line_context = 0; |
215 | 0 | return sres; |
216 | 0 | } |
217 | | |
218 | 3.60k | for (i = 1; i <= dir_count; ++i) { |
219 | 3.28k | dir_name = 0; |
220 | 3.28k | sres = dwarf_srclines_include_dir_data(line_context, i, &dir_name, errp); |
221 | 3.28k | if (sres == DW_DLV_ERROR) { |
222 | 0 | dwarf_srclines_dealloc_b(line_context); |
223 | 0 | line_context = 0; |
224 | 0 | return sres; |
225 | 0 | } |
226 | 3.28k | } |
227 | | |
228 | 313 | sres = dwarf_srclines_from_linecontext(line_context, &linebuf, &linecount, |
229 | 313 | errp); |
230 | 313 | if (sres != DW_DLV_OK) { |
231 | 0 | dwarf_srclines_dealloc_b(line_context); |
232 | 0 | line_context = 0; |
233 | 0 | return sres; |
234 | 0 | } |
235 | 540k | for (i = 0; i < linecount; ++i) { |
236 | 540k | Dwarf_Addr lineaddr = 0; |
237 | 540k | Dwarf_Unsigned filenum = 0; |
238 | 540k | Dwarf_Unsigned lineno = 0; |
239 | 540k | char *linesrcfile = 0; |
240 | | |
241 | 540k | sres = dwarf_lineno(linebuf[i], &lineno, errp); |
242 | 540k | if (sres == DW_DLV_ERROR) { |
243 | 0 | if (prev_linesrcfile) { |
244 | 0 | dwarf_dealloc(dbg, prev_linesrcfile, DW_DLA_STRING); |
245 | 0 | } |
246 | 0 | return sres; |
247 | 0 | } |
248 | 540k | sres = dwarf_line_srcfileno(linebuf[i], &filenum, errp); |
249 | 540k | if (sres == DW_DLV_ERROR) { |
250 | 0 | if (prev_linesrcfile) { |
251 | 0 | dwarf_dealloc(dbg, prev_linesrcfile, DW_DLA_STRING); |
252 | 0 | } |
253 | 0 | return sres; |
254 | 0 | } |
255 | 540k | if (filenum) { |
256 | 524k | filenum -= 1; |
257 | 524k | } |
258 | 540k | sres = dwarf_lineaddr(linebuf[i], &lineaddr, errp); |
259 | 540k | if (sres == DW_DLV_ERROR) { |
260 | 0 | if (prev_linesrcfile) { |
261 | 0 | dwarf_dealloc(dbg, prev_linesrcfile, DW_DLA_STRING); |
262 | 0 | } |
263 | 0 | return sres; |
264 | 0 | } |
265 | 540k | sres = dwarf_linesrc(linebuf[i], &linesrcfile, errp); |
266 | 540k | if (sres == DW_DLV_ERROR) { |
267 | 145 | if (prev_linesrcfile) { |
268 | 129 | dwarf_dealloc(dbg, prev_linesrcfile, DW_DLA_STRING); |
269 | 129 | } |
270 | 145 | return sres; |
271 | 145 | } |
272 | 540k | if (lineaddr > td->td_target_pc) { |
273 | 98 | td->td_subprog_lineaddr = prev_lineaddr; |
274 | 98 | td->td_subprog_lineno = prev_lineno; |
275 | 98 | td->td_subprog_srcfile = prev_linesrcfile; |
276 | 98 | dwarf_dealloc(dbg, linesrcfile, DW_DLA_STRING); |
277 | 98 | return DW_DLV_OK; |
278 | 98 | } |
279 | 540k | prev_lineaddr = lineaddr; |
280 | 540k | prev_lineno = lineno; |
281 | 540k | if (prev_linesrcfile) { |
282 | 523k | dwarf_dealloc(dbg, prev_linesrcfile, DW_DLA_STRING); |
283 | 523k | } |
284 | 540k | prev_linesrcfile = linesrcfile; |
285 | 540k | } |
286 | 70 | td->td_subprog_lineaddr = prev_lineaddr; |
287 | 70 | td->td_subprog_lineno = prev_lineno; |
288 | 70 | td->td_subprog_srcfile = prev_linesrcfile; |
289 | 70 | dwarf_srclines_dealloc_b(line_context); |
290 | 70 | return DW_DLV_OK; |
291 | 313 | } |
292 | 1 | return DW_DLV_ERROR; |
293 | 323 | } |
294 | | |
295 | | static int look_for_our_target(Dwarf_Debug dbg, struct target_data_s *td, |
296 | 9.76k | Dwarf_Error *errp) { |
297 | 9.76k | Dwarf_Unsigned cu_header_length = 0; |
298 | 9.76k | Dwarf_Unsigned abbrev_offset = 0; |
299 | 9.76k | Dwarf_Half address_size = 0; |
300 | 9.76k | Dwarf_Half version_stamp = 0; |
301 | 9.76k | Dwarf_Half offset_size = 0; |
302 | 9.76k | Dwarf_Half extension_size = 0; |
303 | 9.76k | Dwarf_Unsigned typeoffset = 0; |
304 | 9.76k | Dwarf_Half header_cu_type = unittype; |
305 | 9.76k | Dwarf_Bool is_info = g_is_info; |
306 | 9.76k | int cu_number = 0; |
307 | | |
308 | 9.76k | for (;; ++cu_number) { |
309 | 9.76k | Dwarf_Die no_die = 0; |
310 | 9.76k | Dwarf_Die cu_die = 0; |
311 | 9.76k | int res = DW_DLV_ERROR; |
312 | 9.76k | Dwarf_Sig8 signature; |
313 | | |
314 | 9.76k | memset(&signature, 0, sizeof(signature)); |
315 | 9.76k | res = dwarf_next_cu_header_d(dbg, is_info, &cu_header_length, |
316 | 9.76k | &version_stamp, &abbrev_offset, &address_size, |
317 | 9.76k | &offset_size, &extension_size, &signature, |
318 | 9.76k | &typeoffset, 0, &header_cu_type, errp); |
319 | 9.76k | if (res == DW_DLV_ERROR) { |
320 | 3.42k | if (errp) { |
321 | 3.42k | char *em = dwarf_errmsg(*errp); |
322 | 3.42k | } |
323 | 3.42k | return DW_DLV_NO_ENTRY; |
324 | 3.42k | } |
325 | 6.33k | if (res == DW_DLV_NO_ENTRY) { |
326 | 644 | return DW_DLV_NO_ENTRY; |
327 | 644 | } |
328 | 5.69k | cu_version_stamp = version_stamp; |
329 | 5.69k | cu_offset_size = offset_size; |
330 | 5.69k | res = dwarf_siblingof_b(dbg, no_die, is_info, &cu_die, errp); |
331 | 5.69k | if (res == DW_DLV_ERROR) { |
332 | 0 | if (errp) { |
333 | 0 | char *em = dwarf_errmsg(*errp); |
334 | 0 | } |
335 | 0 | return res; |
336 | 0 | } |
337 | 5.69k | if (res == DW_DLV_NO_ENTRY) { |
338 | 274 | return res; |
339 | 274 | } |
340 | | |
341 | 5.42k | td->td_cu_die = cu_die; |
342 | 5.42k | res = get_die_and_siblings(dbg, cu_die, is_info, 0, cu_number, td, errp); |
343 | 5.42k | if (res == FOUND_SUBPROG) { |
344 | 1.30k | read_line_data(dbg, td, errp); |
345 | 1.30k | if (td->td_reportallfound) { |
346 | 0 | return res; |
347 | 0 | } |
348 | 1.30k | return res; |
349 | 4.12k | } else if (res == IN_THIS_CU) { |
350 | 0 | if (errp) { |
351 | 0 | char *em = dwarf_errmsg(*errp); |
352 | 0 | } |
353 | 0 | return res; |
354 | 4.12k | } else if (res == DW_DLV_ERROR) { |
355 | 2.30k | if (errp) { |
356 | 2.30k | char *em = dwarf_errmsg(*errp); |
357 | 2.30k | } |
358 | 2.30k | return DW_DLV_ERROR; |
359 | 2.30k | } |
360 | 1.81k | return DW_DLV_NO_ENTRY; |
361 | 5.42k | } |
362 | 9.76k | } |
363 | | |
364 | | static int get_die_and_siblings(Dwarf_Debug dbg, Dwarf_Die in_die, int is_info, |
365 | | int in_level, int cu_number, |
366 | 284k | struct target_data_s *td, Dwarf_Error *errp) { |
367 | 284k | int res = DW_DLV_ERROR; |
368 | 284k | Dwarf_Die cur_die = in_die; |
369 | 284k | Dwarf_Die child = 0; |
370 | | |
371 | 284k | td->td_cu_number = cu_number; |
372 | 284k | res = examine_die_data(dbg, is_info, in_die, in_level, td, errp); |
373 | 284k | if (res == DW_DLV_ERROR) { |
374 | 546 | return res; |
375 | 546 | } |
376 | 283k | if (res == DW_DLV_NO_ENTRY) { |
377 | 6.34k | return res; |
378 | 6.34k | } |
379 | 277k | if (res == NOT_THIS_CU) { |
380 | 113 | return res; |
381 | 277k | } else if (res == FOUND_SUBPROG) { |
382 | 203 | return res; |
383 | 276k | } else { |
384 | 276k | } |
385 | | |
386 | 9.94M | for (;;) { |
387 | 9.94M | Dwarf_Die sib_die = 0; |
388 | 9.94M | res = dwarf_child(cur_die, &child, errp); |
389 | 9.94M | if (res == DW_DLV_ERROR) { |
390 | 517 | return res; |
391 | 517 | } |
392 | 9.94M | if (res == DW_DLV_OK) { |
393 | 278k | int res2 = 0; |
394 | | |
395 | 278k | res2 = get_die_and_siblings(dbg, child, is_info, in_level + 1, cu_number, |
396 | 278k | td, errp); |
397 | 278k | if (child != td->td_cu_die && child != td->td_subprog_die) { |
398 | 274k | dwarf_dealloc(dbg, child, DW_DLA_DIE); |
399 | 274k | } |
400 | 278k | if (res2 == FOUND_SUBPROG) { |
401 | 3.06k | return res2; |
402 | 275k | } else if (res2 == IN_THIS_CU) { |
403 | 275k | } else if (res2 == NOT_THIS_CU) { |
404 | 7.91k | return res2; |
405 | 267k | } else if (res2 == DW_DLV_ERROR) { |
406 | 61.2k | return res2; |
407 | 206k | } else if (res2 == DW_DLV_NO_ENTRY) { |
408 | 200k | } else { /* DW_DLV_OK */ |
409 | 200k | } |
410 | 206k | child = 0; |
411 | 206k | } |
412 | 9.86M | res = dwarf_siblingof_b(dbg, cur_die, is_info, &sib_die, errp); |
413 | 9.86M | if (res == DW_DLV_ERROR) { |
414 | 1.01k | if (errp) { |
415 | 1.01k | char *em = dwarf_errmsg(*errp); |
416 | 1.01k | } |
417 | 1.01k | return res; |
418 | 1.01k | } |
419 | 9.86M | if (res == DW_DLV_NO_ENTRY) { |
420 | 201k | break; |
421 | 201k | } |
422 | 9.66M | if (cur_die != in_die) { |
423 | 9.47M | if (child != td->td_cu_die && child != td->td_subprog_die) { |
424 | 3.67M | dwarf_dealloc(dbg, cur_die, DW_DLA_DIE); |
425 | 3.67M | } |
426 | 9.47M | cur_die = 0; |
427 | 9.47M | } |
428 | 9.66M | cur_die = sib_die; |
429 | 9.66M | res = examine_die_data(dbg, is_info, cur_die, in_level, td, errp); |
430 | 9.66M | if (res == DW_DLV_ERROR) { |
431 | 236 | return res; |
432 | 9.66M | } else if (res == DW_DLV_OK) { |
433 | 5.68M | } else if (res == FOUND_SUBPROG) { |
434 | 1.09k | return res; |
435 | 5.68M | } else if (res == NOT_THIS_CU) { |
436 | 5.56M | } else if (res == IN_THIS_CU) { |
437 | 113k | } else { |
438 | 113k | } |
439 | 9.66M | } |
440 | 201k | return DW_DLV_OK; |
441 | 276k | } |
442 | | |
443 | | static void dealloc_rest_of_list(Dwarf_Debug dbg, Dwarf_Attribute *attrbuf, |
444 | 74.4k | Dwarf_Signed attrcount, Dwarf_Signed i) { |
445 | 406k | for (; i < attrcount; ++i) { |
446 | 332k | dwarf_dealloc_attribute(attrbuf[i]); |
447 | 332k | } |
448 | 74.4k | dwarf_dealloc(dbg, attrbuf, DW_DLA_LIST); |
449 | 74.4k | } |
450 | | |
451 | | static int getlowhighpc(Dwarf_Die die, int *have_pc_range, |
452 | | Dwarf_Addr *lowpc_out, Dwarf_Addr *highpc_out, |
453 | 150k | Dwarf_Error *error) { |
454 | 150k | Dwarf_Addr hipc = 0; |
455 | 150k | int res = 0; |
456 | 150k | Dwarf_Half form = 0; |
457 | 150k | enum Dwarf_Form_Class formclass = 0; |
458 | | |
459 | 150k | *have_pc_range = FALSE; |
460 | 150k | res = dwarf_lowpc(die, lowpc_out, error); |
461 | 150k | if (res == DW_DLV_OK) { |
462 | 84.1k | res = dwarf_highpc_b(die, &hipc, &form, &formclass, error); |
463 | 84.1k | if (res == DW_DLV_OK) { |
464 | 71.7k | if (formclass == DW_FORM_CLASS_CONSTANT) { |
465 | 6.28k | hipc += *lowpc_out; |
466 | 6.28k | } |
467 | 71.7k | *highpc_out = hipc; |
468 | 71.7k | *have_pc_range = TRUE; |
469 | 71.7k | return DW_DLV_OK; |
470 | 71.7k | } |
471 | 84.1k | } |
472 | 79.0k | return DW_DLV_NO_ENTRY; |
473 | 150k | } |
474 | | |
475 | | static int check_subprog_ranges_for_match(Dwarf_Debug dbg, Dwarf_Die die, |
476 | | struct target_data_s *td, |
477 | | int *have_pc_range, |
478 | | Dwarf_Addr *lowpc_out, |
479 | | Dwarf_Addr *highpc_out, |
480 | 5.61k | Dwarf_Error *errp) { |
481 | 5.61k | int res = 0; |
482 | 5.61k | Dwarf_Ranges *ranges; |
483 | 5.61k | Dwarf_Signed ranges_count; |
484 | 5.61k | Dwarf_Unsigned byte_count; |
485 | 5.61k | Dwarf_Signed i = 0; |
486 | 5.61k | Dwarf_Addr baseaddr = 0; |
487 | 5.61k | Dwarf_Off actualoffset = 0; |
488 | 5.61k | int done = FALSE; |
489 | | |
490 | 5.61k | res = dwarf_get_ranges_b(dbg, td->td_ranges_offset, die, &actualoffset, |
491 | 5.61k | &ranges, &ranges_count, &byte_count, errp); |
492 | 5.61k | if (res != DW_DLV_OK) { |
493 | 4.91k | return res; |
494 | 4.91k | } |
495 | 8.39k | for (i = 0; i < ranges_count && !done; ++i) { |
496 | 7.69k | Dwarf_Ranges *cur = ranges + i; |
497 | 7.69k | Dwarf_Addr lowpc = 0; |
498 | 7.69k | Dwarf_Addr highpc = 0; |
499 | 7.69k | switch (cur->dwr_type) { |
500 | 6.87k | case DW_RANGES_ENTRY: |
501 | 6.87k | lowpc = cur->dwr_addr1 + baseaddr; |
502 | 6.87k | highpc = cur->dwr_addr2 + baseaddr; |
503 | 6.87k | if (td->td_target_pc < lowpc || td->td_target_pc >= highpc) { |
504 | 6.80k | break; |
505 | 6.80k | } |
506 | 78 | *lowpc_out = lowpc; |
507 | 78 | *highpc_out = highpc; |
508 | 78 | *have_pc_range = TRUE; |
509 | 78 | done = TRUE; |
510 | 78 | res = FOUND_SUBPROG; |
511 | 78 | break; |
512 | 345 | case DW_RANGES_ADDRESS_SELECTION: |
513 | 345 | baseaddr = cur->dwr_addr2; |
514 | 345 | break; |
515 | 470 | case DW_RANGES_END: |
516 | 470 | break; |
517 | 0 | default: |
518 | 0 | return DW_DLV_ERROR; |
519 | 7.69k | } |
520 | 7.69k | } |
521 | 703 | dwarf_dealloc_ranges(dbg, ranges, ranges_count); |
522 | 703 | return res; |
523 | 703 | } |
524 | | |
525 | | static int get_name_from_abstract_origin(Dwarf_Debug dbg, int is_info, |
526 | | Dwarf_Die die, char **name, |
527 | 54.3k | Dwarf_Error *errp) { |
528 | 54.3k | int res = 0; |
529 | 54.3k | Dwarf_Die abrootdie = 0; |
530 | 54.3k | Dwarf_Attribute ab_attr = 0; |
531 | 54.3k | Dwarf_Off ab_offset = 0; |
532 | | |
533 | 54.3k | res = dwarf_attr(die, DW_AT_abstract_origin, &ab_attr, errp); |
534 | 54.3k | if (res != DW_DLV_OK) { |
535 | 1.51k | return res; |
536 | 1.51k | } |
537 | | |
538 | 52.8k | res = dwarf_global_formref(ab_attr, &ab_offset, errp); |
539 | 52.8k | if (res != DW_DLV_OK) { |
540 | 10.6k | dwarf_dealloc(dbg, ab_attr, DW_DLA_ATTR); |
541 | 10.6k | return res; |
542 | 10.6k | } |
543 | | |
544 | 42.1k | dwarf_dealloc(dbg, ab_attr, DW_DLA_ATTR); |
545 | 42.1k | res = dwarf_offdie_b(dbg, ab_offset, is_info, &abrootdie, errp); |
546 | 42.1k | if (res != DW_DLV_OK) { |
547 | 33.5k | return res; |
548 | 33.5k | } |
549 | 8.58k | res = dwarf_diename(abrootdie, name, errp); |
550 | 8.58k | dwarf_dealloc_die(abrootdie); |
551 | 8.58k | return res; |
552 | 42.1k | } |
553 | | |
554 | | static int check_subprog_details(Dwarf_Debug dbg, int is_info, Dwarf_Die die, |
555 | | struct target_data_s *td, |
556 | | int *have_pc_range_out, Dwarf_Addr *lowpc_out, |
557 | 133k | Dwarf_Addr *highpc_out, Dwarf_Error *errp) { |
558 | 133k | int res = 0; |
559 | 133k | Dwarf_Addr lowpc = 0; |
560 | 133k | Dwarf_Addr highpc = 0; |
561 | 133k | int finalres = 0; |
562 | 133k | int have_pc_range = FALSE; |
563 | | |
564 | 133k | res = getlowhighpc(die, &have_pc_range, &lowpc, &highpc, errp); |
565 | 133k | if (res == DW_DLV_OK) { |
566 | 69.1k | if (have_pc_range) { |
567 | 69.1k | int res2 = DW_DLV_OK; |
568 | 69.1k | char *name = 0; |
569 | | |
570 | 69.1k | if (td->td_target_pc < lowpc || td->td_target_pc >= highpc) { |
571 | 14.4k | finalres = DW_DLV_OK; |
572 | 54.6k | } else { |
573 | 54.6k | td->td_subprog_die = die; |
574 | 54.6k | td->td_subprog_lowpc = lowpc; |
575 | 54.6k | *lowpc_out = lowpc; |
576 | 54.6k | *highpc_out = highpc; |
577 | 54.6k | *have_pc_range_out = have_pc_range; |
578 | 54.6k | td->td_subprog_highpc = highpc; |
579 | 54.6k | td->td_subprog_haslowhighpc = have_pc_range; |
580 | 54.6k | res2 = dwarf_diename(die, &name, errp); |
581 | 54.6k | if (res2 == DW_DLV_OK) { |
582 | 287 | td->td_subprog_name = name; |
583 | 54.3k | } else { |
584 | 54.3k | get_name_from_abstract_origin(dbg, is_info, die, &name, errp); |
585 | 54.3k | } |
586 | 54.6k | td->td_subprog_name = name; |
587 | 54.6k | name = 0; |
588 | 54.6k | finalres = FOUND_SUBPROG; |
589 | 54.6k | } |
590 | 69.1k | } |
591 | 69.1k | } |
592 | 133k | { |
593 | 133k | Dwarf_Signed i = 0; |
594 | 133k | Dwarf_Signed atcount = 0; |
595 | 133k | Dwarf_Attribute *atlist = 0; |
596 | | |
597 | 133k | res = dwarf_attrlist(die, &atlist, &atcount, errp); |
598 | 133k | if (res != DW_DLV_OK) { |
599 | 31.7k | return res; |
600 | 31.7k | } |
601 | 289k | for (i = 0; i < atcount; ++i) { |
602 | 262k | Dwarf_Half atr = 0; |
603 | 262k | Dwarf_Attribute attrib = atlist[i]; |
604 | | |
605 | 262k | res = dwarf_whatattr(attrib, &atr, errp); |
606 | 262k | if (res != DW_DLV_OK) { |
607 | 0 | dealloc_rest_of_list(dbg, atlist, atcount, i); |
608 | 0 | return res; |
609 | 0 | } |
610 | 262k | if (atr == DW_AT_ranges) { |
611 | 79.9k | int res2 = 0; |
612 | 79.9k | int res4 = 0; |
613 | 79.9k | Dwarf_Off ret_offset = 0; |
614 | 79.9k | int has_low_hi = FALSE; |
615 | 79.9k | Dwarf_Addr low = 0; |
616 | 79.9k | Dwarf_Addr high = 0; |
617 | | |
618 | 79.9k | res2 = dwarf_global_formref(attrib, &ret_offset, errp); |
619 | 79.9k | if (res2 != DW_DLV_OK) { |
620 | 74.3k | dealloc_rest_of_list(dbg, atlist, atcount, i); |
621 | 74.3k | return res2; |
622 | 74.3k | } |
623 | 5.61k | td->td_ranges_offset = ret_offset + td->td_cu_ranges_base; |
624 | 5.61k | res4 = check_subprog_ranges_for_match(dbg, die, td, &has_low_hi, &low, |
625 | 5.61k | &high, errp); |
626 | 5.61k | if (res4 == DW_DLV_OK) { |
627 | 625 | continue; |
628 | 625 | } |
629 | 4.99k | if (res4 == DW_DLV_NO_ENTRY) { |
630 | 4.87k | continue; |
631 | 4.87k | } |
632 | 116 | if (res4 == FOUND_SUBPROG) { |
633 | 78 | td->td_subprog_lowpc = lowpc; |
634 | 78 | td->td_subprog_highpc = highpc; |
635 | 78 | td->td_subprog_haslowhighpc = has_low_hi; |
636 | 78 | finalres = FOUND_SUBPROG; |
637 | 78 | continue; |
638 | 78 | } |
639 | 38 | dealloc_rest_of_list(dbg, atlist, atcount, i); |
640 | 38 | return res4; |
641 | 182k | } else if (atr == DW_AT_decl_file) { |
642 | 6.77k | int res5 = 0; |
643 | 6.77k | Dwarf_Unsigned file_index = 0; |
644 | | |
645 | 6.77k | res5 = dwarf_formudata(attrib, &file_index, errp); |
646 | 6.77k | if (res5 != DW_DLV_OK) { |
647 | 34 | dealloc_rest_of_list(dbg, atlist, atcount, i); |
648 | 34 | return res5; |
649 | 34 | } |
650 | 6.73k | td->td_subprog_fileindex = file_index; |
651 | 6.73k | } |
652 | 182k | dwarf_dealloc(dbg, attrib, DW_DLA_ATTR); |
653 | 182k | } |
654 | 26.9k | dwarf_dealloc(dbg, atlist, DW_DLA_LIST); |
655 | 26.9k | } |
656 | 0 | return finalres; |
657 | 101k | } |
658 | | |
659 | | static int check_comp_dir(Dwarf_Debug dbg, Dwarf_Die die, |
660 | 17.5k | struct target_data_s *td, Dwarf_Error *errp) { |
661 | 17.5k | int res = 0; |
662 | 17.5k | int finalres = DW_DLV_NO_ENTRY; |
663 | 17.5k | int have_pc_range = FALSE; |
664 | 17.5k | Dwarf_Addr lowpc = 0; |
665 | 17.5k | Dwarf_Addr highpc = 0; |
666 | 17.5k | Dwarf_Off real_ranges_offset = 0; |
667 | 17.5k | int rdone = FALSE; |
668 | | |
669 | 17.5k | res = getlowhighpc(die, &have_pc_range, &lowpc, &highpc, errp); |
670 | 17.5k | if (res == DW_DLV_OK) { |
671 | 2.56k | if (have_pc_range) { |
672 | 2.56k | if (td->td_target_pc < lowpc || td->td_target_pc >= highpc) { |
673 | 1.11k | res = NOT_THIS_CU; |
674 | 1.44k | } else { |
675 | 1.44k | td->td_cu_lowpc = lowpc; |
676 | 1.44k | td->td_cu_highpc = highpc; |
677 | 1.44k | res = IN_THIS_CU; |
678 | 1.44k | } |
679 | 2.56k | } |
680 | 2.56k | } |
681 | 17.5k | finalres = res; |
682 | 17.5k | { |
683 | 17.5k | Dwarf_Signed atcount = 0; |
684 | 17.5k | Dwarf_Attribute *atlist = 0; |
685 | 17.5k | Dwarf_Signed j = 0; |
686 | 17.5k | int alres = 0; |
687 | | |
688 | 17.5k | alres = dwarf_attrlist(die, &atlist, &atcount, errp); |
689 | 17.5k | if (alres != DW_DLV_OK) { |
690 | 2.43k | return alres; |
691 | 2.43k | } |
692 | 79.0k | for (j = 0; j < atcount; ++j) { |
693 | 64.0k | Dwarf_Half atr = 0; |
694 | 64.0k | Dwarf_Attribute attrib = atlist[j]; |
695 | 64.0k | int resb = 0; |
696 | | |
697 | 64.0k | resb = dwarf_whatattr(attrib, &atr, errp); |
698 | 64.0k | if (resb != DW_DLV_OK) { |
699 | 0 | dwarf_dealloc(dbg, atlist, DW_DLA_LIST); |
700 | 0 | return resb; |
701 | 0 | } |
702 | 64.0k | if (atr == DW_AT_name) { |
703 | 12.9k | char *name = 0; |
704 | 12.9k | resb = dwarf_formstring(attrib, &name, errp); |
705 | 12.9k | if (resb == DW_DLV_OK) { |
706 | 641 | td->td_cu_name = name; |
707 | 641 | } |
708 | 51.0k | } else if (atr == DW_AT_comp_dir) { |
709 | 6.65k | char *name = 0; |
710 | 6.65k | resb = dwarf_formstring(attrib, &name, errp); |
711 | 6.65k | if (resb == DW_DLV_OK) { |
712 | 136 | td->td_cu_comp_dir = name; |
713 | 136 | } |
714 | 44.4k | } else if (atr == DW_AT_rnglists_base || atr == DW_AT_GNU_ranges_base) { |
715 | 993 | Dwarf_Off rbase = 0; |
716 | | |
717 | 993 | resb = dwarf_global_formref(attrib, &rbase, errp); |
718 | 993 | if (resb != DW_DLV_OK) { |
719 | 174 | dwarf_dealloc(dbg, atlist, DW_DLA_LIST); |
720 | 174 | return resb; |
721 | 174 | } |
722 | 819 | td->td_cu_ranges_base = rbase; |
723 | 43.4k | } else if (atr == DW_AT_ranges) { |
724 | | /* we have actual ranges. */ |
725 | 1.31k | Dwarf_Off rbase = 0; |
726 | | |
727 | 1.31k | resb = dwarf_global_formref(attrib, &rbase, errp); |
728 | 1.31k | if (resb != DW_DLV_OK) { |
729 | 41 | dwarf_dealloc(dbg, atlist, DW_DLA_LIST); |
730 | 41 | return resb; |
731 | 41 | } |
732 | 1.27k | real_ranges_offset = rbase; |
733 | 1.27k | rdone = TRUE; |
734 | 1.27k | } |
735 | 63.8k | dwarf_dealloc(dbg, attrib, DW_DLA_ATTR); |
736 | 63.8k | } |
737 | 14.9k | dwarf_dealloc(dbg, atlist, DW_DLA_LIST); |
738 | 14.9k | } |
739 | 14.9k | if (rdone) { |
740 | 1.27k | int resr = 0; |
741 | 1.27k | Dwarf_Ranges *ranges = 0; |
742 | 1.27k | Dwarf_Signed ranges_count = 0; |
743 | 1.27k | Dwarf_Unsigned byte_count = 0; |
744 | 1.27k | Dwarf_Off actualoffset = 0; |
745 | 1.27k | Dwarf_Signed k = 0; |
746 | 1.27k | int done = FALSE; |
747 | | |
748 | 1.27k | resr = dwarf_get_ranges_b(dbg, real_ranges_offset, die, &actualoffset, |
749 | 1.27k | &ranges, &ranges_count, &byte_count, errp); |
750 | 1.27k | if (resr != DW_DLV_OK) { |
751 | 734 | return res; |
752 | 734 | } |
753 | 8.04k | for (k = 0; k < ranges_count && !done; ++k) { |
754 | 7.50k | Dwarf_Ranges *cur = ranges + k; |
755 | 7.50k | Dwarf_Addr lowpcr = 0; |
756 | 7.50k | Dwarf_Addr highpcr = 0; |
757 | 7.50k | Dwarf_Addr baseaddr = td->td_cu_ranges_base; |
758 | | |
759 | 7.50k | switch (cur->dwr_type) { |
760 | 7.10k | case DW_RANGES_ENTRY: |
761 | 7.10k | lowpc = cur->dwr_addr1 + baseaddr; |
762 | 7.10k | highpc = cur->dwr_addr2 + baseaddr; |
763 | 7.10k | if (td->td_target_pc < lowpc || td->td_target_pc >= highpc) { |
764 | 6.85k | break; |
765 | 6.85k | } |
766 | 242 | td->td_cu_lowpc = lowpcr; |
767 | 242 | td->td_cu_highpc = highpcr; |
768 | 242 | td->td_cu_haslowhighpc = TRUE; |
769 | 242 | done = TRUE; |
770 | 242 | finalres = IN_THIS_CU; |
771 | 242 | break; |
772 | 220 | case DW_RANGES_ADDRESS_SELECTION: |
773 | 220 | baseaddr = cur->dwr_addr2; |
774 | 220 | break; |
775 | 182 | case DW_RANGES_END: |
776 | 182 | break; |
777 | 0 | default: |
778 | 0 | return DW_DLV_ERROR; |
779 | 7.50k | } |
780 | 7.50k | } |
781 | 538 | dwarf_dealloc_ranges(dbg, ranges, ranges_count); |
782 | 538 | } |
783 | 14.2k | return finalres; |
784 | 14.9k | } |
785 | | |
786 | | static int examine_die_data(Dwarf_Debug dbg, int is_info, Dwarf_Die die, |
787 | | int level, struct target_data_s *td, |
788 | 9.95M | Dwarf_Error *errp) { |
789 | 9.95M | Dwarf_Half tag = 0; |
790 | 9.95M | int res = 0; |
791 | | |
792 | 9.95M | res = dwarf_tag(die, &tag, errp); |
793 | 9.95M | if (res != DW_DLV_OK) { |
794 | 0 | return res; |
795 | 0 | } |
796 | 9.95M | if (tag == DW_TAG_subprogram || tag == DW_TAG_inlined_subroutine) { |
797 | 133k | int have_pc_range = 0; |
798 | 133k | Dwarf_Addr lowpc = 0; |
799 | 133k | Dwarf_Addr highpc = 0; |
800 | | |
801 | 133k | res = check_subprog_details(dbg, is_info, die, td, &have_pc_range, &lowpc, |
802 | 133k | &highpc, errp); |
803 | 133k | if (res == FOUND_SUBPROG) { |
804 | 1.30k | td->td_subprog_die = die; |
805 | 1.30k | return res; |
806 | 131k | } else if (res == DW_DLV_ERROR) { |
807 | 611 | return res; |
808 | 131k | } else if (res == DW_DLV_NO_ENTRY) { |
809 | | /* impossible? */ |
810 | 105k | return res; |
811 | 105k | } else if (res == NOT_THIS_CU) { |
812 | | /* impossible */ |
813 | 0 | return res; |
814 | 25.6k | } else if (res == IN_THIS_CU) { |
815 | | /* impossible */ |
816 | 0 | return res; |
817 | 25.6k | } else { |
818 | | /* DW_DLV_OK */ |
819 | 25.6k | } |
820 | 25.6k | return DW_DLV_OK; |
821 | 9.81M | } else if (tag == DW_TAG_compile_unit || tag == DW_TAG_partial_unit || |
822 | 9.81M | tag == DW_TAG_type_unit) { |
823 | | |
824 | 5.58M | if (level) { |
825 | 5.56M | return NOT_THIS_CU; |
826 | 5.56M | } |
827 | 17.5k | res = check_comp_dir(dbg, die, td, errp); |
828 | 17.5k | return res; |
829 | 5.58M | } |
830 | 4.23M | return DW_DLV_OK; |
831 | 9.95M | } |