/src/libdwarf/fuzz/fuzz_findfuncbypc.c
Line | Count | Source |
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.9k | #define TRUE 1 |
32 | 342k | #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 | 9.99M | #define NOT_THIS_CU 10 |
73 | 392k | #define IN_THIS_CU 11 |
74 | 5.47M | #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 | 15.3k | int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { |
95 | 15.3k | char filename[256]; |
96 | | |
97 | | #ifdef DWREGRESSIONTEMP |
98 | | /* under msys2, the /tmp/ results in an open fail, |
99 | | so we discard the /tmp/. No need for |
100 | | /tmp/ in Linux anyway. libdwarf regressiontests |
101 | | use it this way. */ |
102 | | sprintf(filename, "junklibfuzzer.%d", getpid()); |
103 | | #else |
104 | 15.3k | sprintf(filename, "/tmp/libfuzzer.%d", getpid()); |
105 | 15.3k | #endif |
106 | 15.3k | FILE *fp = fopen(filename, "wb"); |
107 | 15.3k | if (!fp) { |
108 | 0 | printf("FAIL libfuzzer cannot open temp as writeable %s\n", |
109 | 0 | filename); |
110 | 0 | return 0; |
111 | 0 | } |
112 | 15.3k | fwrite(data, size, 1, fp); |
113 | 15.3k | fclose(fp); |
114 | | |
115 | 15.3k | Dwarf_Debug dbg = 0; |
116 | 15.3k | Dwarf_Error error = 0; |
117 | 15.3k | Dwarf_Handler errhand = 0; |
118 | 15.3k | Dwarf_Ptr errarg = 0; |
119 | 15.3k | int i = 0; |
120 | 15.3k | Dwarf_Unsigned target_pc = 0x1000; |
121 | 15.3k | #define PATH_LEN 2000 |
122 | 15.3k | char real_path[PATH_LEN]; |
123 | 15.3k | struct target_data_s target_data; |
124 | | |
125 | | /* Added 19 May 2023 so valgrind will not complain |
126 | | about testing uninitialized values in |
127 | | check_coup_dir (for example). */ |
128 | 15.3k | memset(&target_data,0,sizeof(target_data)); |
129 | 15.3k | int res = |
130 | 15.3k | dwarf_init_path(filename, 0, 0, DW_GROUPNUMBER_ANY, 0, 0, &dbg, &error); |
131 | 15.3k | if (res == DW_DLV_ERROR) { |
132 | 5.03k | dwarf_dealloc_error(dbg, error); |
133 | 5.03k | dwarf_finish(dbg); |
134 | 10.3k | } else { |
135 | 10.3k | res = look_for_our_target(dbg, &target_data, &error); |
136 | 10.3k | res = dwarf_finish(dbg); |
137 | 10.3k | } |
138 | | |
139 | 15.3k | unlink(filename); |
140 | 15.3k | return 0; |
141 | 15.3k | } |
142 | | |
143 | | static int read_line_data(Dwarf_Debug dbg, struct target_data_s *td, |
144 | 1.24k | Dwarf_Error *errp) { |
145 | 1.24k | int res = 0; |
146 | 1.24k | Dwarf_Unsigned line_version = 0; |
147 | 1.24k | Dwarf_Small table_type = 0; |
148 | 1.24k | Dwarf_Line_Context line_context = 0; |
149 | 1.24k | Dwarf_Signed i = 0; |
150 | 1.24k | Dwarf_Signed baseindex = 0; |
151 | 1.24k | Dwarf_Signed endindex = 0; |
152 | 1.24k | Dwarf_Signed file_count = 0; |
153 | 1.24k | Dwarf_Unsigned dirindex = 0; |
154 | | |
155 | 1.24k | (void)dbg; |
156 | 1.24k | res = dwarf_srclines_b(td->td_cu_die, &line_version, &table_type, |
157 | 1.24k | &line_context, errp); |
158 | 1.24k | if (res != DW_DLV_OK) { |
159 | 940 | return res; |
160 | 940 | } |
161 | 304 | if (table_type == 0) { |
162 | 9 | int sres = 0; |
163 | | |
164 | 9 | sres = dwarf_srclines_files_indexes(line_context, &baseindex, &file_count, |
165 | 9 | &endindex, errp); |
166 | 9 | if (sres != DW_DLV_OK) { |
167 | 0 | dwarf_srclines_dealloc_b(line_context); |
168 | 0 | line_context = 0; |
169 | 0 | return sres; |
170 | 0 | } |
171 | 100 | for (i = baseindex; i < endindex; i++) { |
172 | 91 | Dwarf_Unsigned modtime = 0; |
173 | 91 | Dwarf_Unsigned flength = 0; |
174 | 91 | Dwarf_Form_Data16 *md5data = 0; |
175 | 91 | int vres = 0; |
176 | 91 | const char *name = 0; |
177 | | |
178 | 91 | vres = dwarf_srclines_files_data_b(line_context, i, &name, &dirindex, |
179 | 91 | &modtime, &flength, &md5data, errp); |
180 | 91 | if (vres != DW_DLV_OK) { |
181 | 0 | dwarf_srclines_dealloc_b(line_context); |
182 | 0 | line_context = 0; |
183 | 0 | return vres; |
184 | 0 | } |
185 | 91 | } |
186 | 9 | dwarf_srclines_dealloc_b(line_context); |
187 | 9 | return DW_DLV_OK; |
188 | 295 | } else if (table_type == 1) { |
189 | 294 | const char *dir_name = 0; |
190 | 294 | int sres = 0; |
191 | 294 | Dwarf_Line *linebuf = 0; |
192 | 294 | Dwarf_Signed linecount = 0; |
193 | 294 | Dwarf_Signed dir_count = 0; |
194 | 294 | Dwarf_Addr prev_lineaddr = 0; |
195 | 294 | Dwarf_Unsigned prev_lineno = 0; |
196 | 294 | char *prev_linesrcfile = 0; |
197 | | |
198 | 294 | sres = dwarf_srclines_files_indexes(line_context, &baseindex, &file_count, |
199 | 294 | &endindex, errp); |
200 | 294 | if (sres != DW_DLV_OK) { |
201 | 0 | dwarf_srclines_dealloc_b(line_context); |
202 | 0 | line_context = 0; |
203 | 0 | return sres; |
204 | 0 | } |
205 | 17.6k | for (i = baseindex; i < endindex; i++) { |
206 | 17.3k | Dwarf_Unsigned dirindexb = 0; |
207 | 17.3k | Dwarf_Unsigned modtime = 0; |
208 | 17.3k | Dwarf_Unsigned flength = 0; |
209 | 17.3k | Dwarf_Form_Data16 *md5data = 0; |
210 | 17.3k | int vres = 0; |
211 | 17.3k | const char *name = 0; |
212 | | |
213 | 17.3k | vres = dwarf_srclines_files_data_b(line_context, i, &name, &dirindexb, |
214 | 17.3k | &modtime, &flength, &md5data, errp); |
215 | 17.3k | if (vres != DW_DLV_OK) { |
216 | 0 | dwarf_srclines_dealloc_b(line_context); |
217 | 0 | line_context = 0; |
218 | 0 | return vres; |
219 | 0 | } |
220 | 17.3k | } |
221 | 294 | sres = dwarf_srclines_include_dir_count(line_context, &dir_count, errp); |
222 | 294 | if (sres != DW_DLV_OK) { |
223 | 0 | dwarf_srclines_dealloc_b(line_context); |
224 | 0 | line_context = 0; |
225 | 0 | return sres; |
226 | 0 | } |
227 | | |
228 | 3.42k | for (i = 1; i <= dir_count; ++i) { |
229 | 3.12k | dir_name = 0; |
230 | 3.12k | sres = dwarf_srclines_include_dir_data(line_context, i, &dir_name, errp); |
231 | 3.12k | if (sres == DW_DLV_ERROR) { |
232 | 0 | dwarf_srclines_dealloc_b(line_context); |
233 | 0 | line_context = 0; |
234 | 0 | return sres; |
235 | 0 | } |
236 | 3.12k | } |
237 | | |
238 | 294 | sres = dwarf_srclines_from_linecontext(line_context, &linebuf, &linecount, |
239 | 294 | errp); |
240 | 294 | if (sres != DW_DLV_OK) { |
241 | 0 | dwarf_srclines_dealloc_b(line_context); |
242 | 0 | line_context = 0; |
243 | 0 | return sres; |
244 | 0 | } |
245 | 290k | for (i = 0; i < linecount; ++i) { |
246 | 290k | Dwarf_Addr lineaddr = 0; |
247 | 290k | Dwarf_Unsigned filenum = 0; |
248 | 290k | Dwarf_Unsigned lineno = 0; |
249 | 290k | char *linesrcfile = 0; |
250 | | |
251 | 290k | sres = dwarf_lineno(linebuf[i], &lineno, errp); |
252 | 290k | if (sres == DW_DLV_ERROR) { |
253 | 0 | if (prev_linesrcfile) { |
254 | 0 | dwarf_dealloc(dbg, prev_linesrcfile, DW_DLA_STRING); |
255 | 0 | } |
256 | 0 | return sres; |
257 | 0 | } |
258 | 290k | sres = dwarf_line_srcfileno(linebuf[i], &filenum, errp); |
259 | 290k | 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 | 290k | if (filenum) { |
266 | 279k | filenum -= 1; |
267 | 279k | } |
268 | 290k | sres = dwarf_lineaddr(linebuf[i], &lineaddr, errp); |
269 | 290k | if (sres == DW_DLV_ERROR) { |
270 | 0 | if (prev_linesrcfile) { |
271 | 0 | dwarf_dealloc(dbg, prev_linesrcfile, DW_DLA_STRING); |
272 | 0 | } |
273 | 0 | return sres; |
274 | 0 | } |
275 | 290k | sres = dwarf_linesrc(linebuf[i], &linesrcfile, errp); |
276 | 290k | if (sres == DW_DLV_ERROR) { |
277 | 151 | if (prev_linesrcfile) { |
278 | 129 | dwarf_dealloc(dbg, prev_linesrcfile, DW_DLA_STRING); |
279 | 129 | } |
280 | 151 | return sres; |
281 | 151 | } |
282 | 290k | if (lineaddr > td->td_target_pc) { |
283 | 85 | td->td_subprog_lineaddr = prev_lineaddr; |
284 | 85 | td->td_subprog_lineno = prev_lineno; |
285 | 85 | td->td_subprog_srcfile = prev_linesrcfile; |
286 | 85 | dwarf_dealloc(dbg, linesrcfile, DW_DLA_STRING); |
287 | 85 | return DW_DLV_OK; |
288 | 85 | } |
289 | 290k | prev_lineaddr = lineaddr; |
290 | 290k | prev_lineno = lineno; |
291 | 290k | if (prev_linesrcfile) { |
292 | 278k | dwarf_dealloc(dbg, prev_linesrcfile, DW_DLA_STRING); |
293 | 278k | } |
294 | 290k | prev_linesrcfile = linesrcfile; |
295 | 290k | } |
296 | 58 | td->td_subprog_lineaddr = prev_lineaddr; |
297 | 58 | td->td_subprog_lineno = prev_lineno; |
298 | 58 | td->td_subprog_srcfile = prev_linesrcfile; |
299 | 58 | dwarf_srclines_dealloc_b(line_context); |
300 | 58 | return DW_DLV_OK; |
301 | 294 | } |
302 | 1 | return DW_DLV_ERROR; |
303 | 304 | } |
304 | | |
305 | | static int look_for_our_target(Dwarf_Debug dbg, struct target_data_s *td, |
306 | 10.3k | Dwarf_Error *errp) { |
307 | 10.3k | Dwarf_Unsigned cu_header_length = 0; |
308 | 10.3k | Dwarf_Unsigned abbrev_offset = 0; |
309 | 10.3k | Dwarf_Half address_size = 0; |
310 | 10.3k | Dwarf_Half version_stamp = 0; |
311 | 10.3k | Dwarf_Half offset_size = 0; |
312 | 10.3k | Dwarf_Half extension_size = 0; |
313 | 10.3k | Dwarf_Unsigned typeoffset = 0; |
314 | 10.3k | Dwarf_Half header_cu_type = unittype; |
315 | 10.3k | Dwarf_Bool is_info = g_is_info; |
316 | 10.3k | int cu_number = 0; |
317 | | |
318 | 10.3k | for (;; ++cu_number) { |
319 | 10.3k | Dwarf_Die no_die = 0; |
320 | 10.3k | Dwarf_Die cu_die = 0; |
321 | 10.3k | int res = DW_DLV_ERROR; |
322 | 10.3k | Dwarf_Sig8 signature; |
323 | | |
324 | 10.3k | memset(&signature, 0, sizeof(signature)); |
325 | 10.3k | res = dwarf_next_cu_header_d(dbg, is_info, &cu_header_length, |
326 | 10.3k | &version_stamp, &abbrev_offset, &address_size, |
327 | 10.3k | &offset_size, &extension_size, &signature, |
328 | 10.3k | &typeoffset, 0, &header_cu_type, errp); |
329 | 10.3k | if (res == DW_DLV_ERROR) { |
330 | 3.84k | if (errp) { |
331 | 3.84k | char *em = dwarf_errmsg(*errp); |
332 | 3.84k | } |
333 | 3.84k | return DW_DLV_NO_ENTRY; |
334 | 3.84k | } |
335 | 6.50k | if (res == DW_DLV_NO_ENTRY) { |
336 | 608 | return DW_DLV_NO_ENTRY; |
337 | 608 | } |
338 | 5.89k | cu_version_stamp = version_stamp; |
339 | 5.89k | cu_offset_size = offset_size; |
340 | 5.89k | res = dwarf_siblingof_b(dbg, no_die, is_info, &cu_die, errp); |
341 | 5.89k | if (res == DW_DLV_ERROR) { |
342 | 0 | if (errp) { |
343 | 0 | char *em = dwarf_errmsg(*errp); |
344 | 0 | } |
345 | 0 | return res; |
346 | 0 | } |
347 | 5.89k | if (res == DW_DLV_NO_ENTRY) { |
348 | 355 | return res; |
349 | 355 | } |
350 | | |
351 | 5.53k | td->td_cu_die = cu_die; |
352 | 5.53k | res = get_die_and_siblings(dbg, cu_die, is_info, 0, cu_number, td, errp); |
353 | 5.53k | if (res == FOUND_SUBPROG) { |
354 | 1.24k | read_line_data(dbg, td, errp); |
355 | 1.24k | if (td->td_reportallfound) { |
356 | 0 | return res; |
357 | 0 | } |
358 | 1.24k | return res; |
359 | 4.29k | } else if (res == IN_THIS_CU) { |
360 | 0 | if (errp) { |
361 | 0 | char *em = dwarf_errmsg(*errp); |
362 | 0 | } |
363 | 0 | return res; |
364 | 4.29k | } else if (res == DW_DLV_ERROR) { |
365 | 2.26k | if (errp) { |
366 | 2.26k | char *em = dwarf_errmsg(*errp); |
367 | 2.26k | } |
368 | 2.26k | return DW_DLV_ERROR; |
369 | 2.26k | } |
370 | 2.02k | return DW_DLV_NO_ENTRY; |
371 | 5.53k | } |
372 | 10.3k | } |
373 | | |
374 | | static int get_die_and_siblings(Dwarf_Debug dbg, Dwarf_Die in_die, int is_info, |
375 | | int in_level, int cu_number, |
376 | 289k | struct target_data_s *td, Dwarf_Error *errp) { |
377 | 289k | int res = DW_DLV_ERROR; |
378 | 289k | Dwarf_Die cur_die = in_die; |
379 | 289k | Dwarf_Die child = 0; |
380 | | |
381 | 289k | td->td_cu_number = cu_number; |
382 | 289k | res = examine_die_data(dbg, is_info, in_die, in_level, td, errp); |
383 | 289k | if (res == DW_DLV_ERROR) { |
384 | 453 | return res; |
385 | 453 | } |
386 | 288k | if (res == DW_DLV_NO_ENTRY) { |
387 | 8.05k | return res; |
388 | 8.05k | } |
389 | 280k | if (res == NOT_THIS_CU) { |
390 | 71 | return res; |
391 | 280k | } else if (res == FOUND_SUBPROG) { |
392 | 216 | return res; |
393 | 280k | } else { |
394 | 280k | } |
395 | | |
396 | 9.89M | for (;;) { |
397 | 9.89M | Dwarf_Die sib_die = 0; |
398 | 9.89M | res = dwarf_child(cur_die, &child, errp); |
399 | 9.89M | if (res == DW_DLV_ERROR) { |
400 | 562 | return res; |
401 | 562 | } |
402 | 9.89M | if (res == DW_DLV_OK) { |
403 | 283k | int res2 = 0; |
404 | | |
405 | 283k | res2 = get_die_and_siblings(dbg, child, is_info, in_level + 1, cu_number, |
406 | 283k | td, errp); |
407 | 283k | if (child != td->td_cu_die && child != td->td_subprog_die) { |
408 | 277k | dwarf_dealloc(dbg, child, DW_DLA_DIE); |
409 | 277k | } |
410 | 283k | if (res2 == FOUND_SUBPROG) { |
411 | 2.85k | return res2; |
412 | 280k | } else if (res2 == IN_THIS_CU) { |
413 | 280k | } else if (res2 == NOT_THIS_CU) { |
414 | 3.31k | return res2; |
415 | 277k | } else if (res2 == DW_DLV_ERROR) { |
416 | 56.4k | return res2; |
417 | 220k | } else if (res2 == DW_DLV_NO_ENTRY) { |
418 | 213k | } else { /* DW_DLV_OK */ |
419 | 213k | } |
420 | 220k | child = 0; |
421 | 220k | } |
422 | 9.83M | res = dwarf_siblingof_b(dbg, cur_die, is_info, &sib_die, errp); |
423 | 9.83M | if (res == DW_DLV_ERROR) { |
424 | 999 | if (errp) { |
425 | 999 | char *em = dwarf_errmsg(*errp); |
426 | 999 | } |
427 | 999 | return res; |
428 | 999 | } |
429 | 9.83M | if (res == DW_DLV_NO_ENTRY) { |
430 | 214k | break; |
431 | 214k | } |
432 | 9.61M | if (cur_die != in_die) { |
433 | 9.41M | if (child != td->td_cu_die && child != td->td_subprog_die) { |
434 | 3.80M | dwarf_dealloc(dbg, cur_die, DW_DLA_DIE); |
435 | 3.80M | } |
436 | 9.41M | cur_die = 0; |
437 | 9.41M | } |
438 | 9.61M | cur_die = sib_die; |
439 | 9.61M | res = examine_die_data(dbg, is_info, cur_die, in_level, td, errp); |
440 | 9.61M | if (res == DW_DLV_ERROR) { |
441 | 252 | return res; |
442 | 9.61M | } else if (res == DW_DLV_OK) { |
443 | 4.86M | } else if (res == FOUND_SUBPROG) { |
444 | 1.02k | return res; |
445 | 4.74M | } else if (res == NOT_THIS_CU) { |
446 | 4.66M | } else if (res == IN_THIS_CU) { |
447 | 83.4k | } else { |
448 | 83.4k | } |
449 | 9.61M | } |
450 | 214k | return DW_DLV_OK; |
451 | 280k | } |
452 | | |
453 | | static void dealloc_rest_of_list(Dwarf_Debug dbg, Dwarf_Attribute *attrbuf, |
454 | 78.1k | Dwarf_Signed attrcount, Dwarf_Signed i) { |
455 | 426k | for (; i < attrcount; ++i) { |
456 | 348k | dwarf_dealloc_attribute(attrbuf[i]); |
457 | 348k | } |
458 | 78.1k | dwarf_dealloc(dbg, attrbuf, DW_DLA_LIST); |
459 | 78.1k | } |
460 | | |
461 | | static int getlowhighpc(Dwarf_Die die, int *have_pc_range, |
462 | | Dwarf_Addr *lowpc_out, Dwarf_Addr *highpc_out, |
463 | 118k | Dwarf_Error *error) { |
464 | 118k | Dwarf_Addr hipc = 0; |
465 | 118k | int res = 0; |
466 | 118k | Dwarf_Half form = 0; |
467 | 118k | enum Dwarf_Form_Class formclass = 0; |
468 | | |
469 | 118k | *have_pc_range = FALSE; |
470 | 118k | res = dwarf_lowpc(die, lowpc_out, error); |
471 | 118k | if (res == DW_DLV_OK) { |
472 | 82.8k | res = dwarf_highpc_b(die, &hipc, &form, &formclass, error); |
473 | 82.8k | if (res == DW_DLV_OK) { |
474 | 71.5k | if (formclass == DW_FORM_CLASS_CONSTANT) { |
475 | 8.49k | hipc += *lowpc_out; |
476 | 8.49k | } |
477 | 71.5k | *highpc_out = hipc; |
478 | 71.5k | *have_pc_range = TRUE; |
479 | 71.5k | return DW_DLV_OK; |
480 | 71.5k | } |
481 | 82.8k | } |
482 | 46.5k | return DW_DLV_NO_ENTRY; |
483 | 118k | } |
484 | | |
485 | | static int check_subprog_ranges_for_match(Dwarf_Debug dbg, Dwarf_Die die, |
486 | | struct target_data_s *td, |
487 | | int *have_pc_range, |
488 | | Dwarf_Addr *lowpc_out, |
489 | | Dwarf_Addr *highpc_out, |
490 | 6.42k | Dwarf_Error *errp) { |
491 | 6.42k | int res = 0; |
492 | 6.42k | Dwarf_Ranges *ranges; |
493 | 6.42k | Dwarf_Signed ranges_count; |
494 | 6.42k | Dwarf_Unsigned byte_count; |
495 | 6.42k | Dwarf_Signed i = 0; |
496 | 6.42k | Dwarf_Addr baseaddr = 0; |
497 | 6.42k | Dwarf_Off actualoffset = 0; |
498 | 6.42k | int done = FALSE; |
499 | | |
500 | 6.42k | res = dwarf_get_ranges_b(dbg, td->td_ranges_offset, die, &actualoffset, |
501 | 6.42k | &ranges, &ranges_count, &byte_count, errp); |
502 | 6.42k | if (res != DW_DLV_OK) { |
503 | 5.92k | return res; |
504 | 5.92k | } |
505 | 6.24k | for (i = 0; i < ranges_count && !done; ++i) { |
506 | 5.73k | Dwarf_Ranges *cur = ranges + i; |
507 | 5.73k | Dwarf_Addr lowpc = 0; |
508 | 5.73k | Dwarf_Addr highpc = 0; |
509 | 5.73k | switch (cur->dwr_type) { |
510 | 5.10k | case DW_RANGES_ENTRY: |
511 | 5.10k | lowpc = cur->dwr_addr1 + baseaddr; |
512 | 5.10k | highpc = cur->dwr_addr2 + baseaddr; |
513 | 5.10k | if (td->td_target_pc < lowpc || td->td_target_pc >= highpc) { |
514 | 5.03k | break; |
515 | 5.03k | } |
516 | 70 | *lowpc_out = lowpc; |
517 | 70 | *highpc_out = highpc; |
518 | 70 | *have_pc_range = TRUE; |
519 | 70 | done = TRUE; |
520 | 70 | res = FOUND_SUBPROG; |
521 | 70 | break; |
522 | 336 | case DW_RANGES_ADDRESS_SELECTION: |
523 | 336 | baseaddr = cur->dwr_addr2; |
524 | 336 | break; |
525 | 297 | case DW_RANGES_END: |
526 | 297 | break; |
527 | 0 | default: |
528 | 0 | return DW_DLV_ERROR; |
529 | 5.73k | } |
530 | 5.73k | } |
531 | 501 | dwarf_dealloc_ranges(dbg, ranges, ranges_count); |
532 | 501 | return res; |
533 | 501 | } |
534 | | |
535 | | static int get_name_from_abstract_origin(Dwarf_Debug dbg, int is_info, |
536 | | Dwarf_Die die, char **name, |
537 | 53.9k | Dwarf_Error *errp) { |
538 | 53.9k | int res = 0; |
539 | 53.9k | Dwarf_Die abrootdie = 0; |
540 | 53.9k | Dwarf_Attribute ab_attr = 0; |
541 | 53.9k | Dwarf_Off ab_offset = 0; |
542 | | |
543 | 53.9k | res = dwarf_attr(die, DW_AT_abstract_origin, &ab_attr, errp); |
544 | 53.9k | if (res != DW_DLV_OK) { |
545 | 1.82k | return res; |
546 | 1.82k | } |
547 | | |
548 | 52.1k | res = dwarf_global_formref(ab_attr, &ab_offset, errp); |
549 | 52.1k | if (res != DW_DLV_OK) { |
550 | 10.0k | dwarf_dealloc(dbg, ab_attr, DW_DLA_ATTR); |
551 | 10.0k | return res; |
552 | 10.0k | } |
553 | | |
554 | 42.0k | dwarf_dealloc(dbg, ab_attr, DW_DLA_ATTR); |
555 | 42.0k | res = dwarf_offdie_b(dbg, ab_offset, is_info, &abrootdie, errp); |
556 | 42.0k | if (res != DW_DLV_OK) { |
557 | 34.0k | return res; |
558 | 34.0k | } |
559 | 7.98k | res = dwarf_diename(abrootdie, name, errp); |
560 | 7.98k | dwarf_dealloc_die(abrootdie); |
561 | 7.98k | return res; |
562 | 42.0k | } |
563 | | |
564 | | static int check_subprog_details(Dwarf_Debug dbg, int is_info, Dwarf_Die die, |
565 | | struct target_data_s *td, |
566 | | int *have_pc_range_out, Dwarf_Addr *lowpc_out, |
567 | 104k | Dwarf_Addr *highpc_out, Dwarf_Error *errp) { |
568 | 104k | int res = 0; |
569 | 104k | Dwarf_Addr lowpc = 0; |
570 | 104k | Dwarf_Addr highpc = 0; |
571 | 104k | int finalres = 0; |
572 | 104k | int have_pc_range = FALSE; |
573 | | |
574 | 104k | res = getlowhighpc(die, &have_pc_range, &lowpc, &highpc, errp); |
575 | 104k | if (res == DW_DLV_OK) { |
576 | 69.7k | if (have_pc_range) { |
577 | 69.7k | int res2 = DW_DLV_OK; |
578 | 69.7k | char *name = 0; |
579 | | |
580 | 69.7k | if (td->td_target_pc < lowpc || td->td_target_pc >= highpc) { |
581 | 15.4k | finalres = DW_DLV_OK; |
582 | 54.2k | } else { |
583 | 54.2k | td->td_subprog_die = die; |
584 | 54.2k | td->td_subprog_lowpc = lowpc; |
585 | 54.2k | *lowpc_out = lowpc; |
586 | 54.2k | *highpc_out = highpc; |
587 | 54.2k | *have_pc_range_out = have_pc_range; |
588 | 54.2k | td->td_subprog_highpc = highpc; |
589 | 54.2k | td->td_subprog_haslowhighpc = have_pc_range; |
590 | 54.2k | res2 = dwarf_diename(die, &name, errp); |
591 | 54.2k | if (res2 == DW_DLV_OK) { |
592 | 300 | td->td_subprog_name = name; |
593 | 53.9k | } else { |
594 | 53.9k | get_name_from_abstract_origin(dbg, is_info, die, &name, errp); |
595 | 53.9k | } |
596 | 54.2k | td->td_subprog_name = name; |
597 | 54.2k | name = 0; |
598 | 54.2k | finalres = FOUND_SUBPROG; |
599 | 54.2k | } |
600 | 69.7k | } |
601 | 69.7k | } |
602 | 104k | { |
603 | 104k | Dwarf_Signed i = 0; |
604 | 104k | Dwarf_Signed atcount = 0; |
605 | 104k | Dwarf_Attribute *atlist = 0; |
606 | | |
607 | 104k | res = dwarf_attrlist(die, &atlist, &atcount, errp); |
608 | 104k | if (res != DW_DLV_OK) { |
609 | 2.55k | return res; |
610 | 2.55k | } |
611 | 284k | for (i = 0; i < atcount; ++i) { |
612 | 260k | Dwarf_Half atr = 0; |
613 | 260k | Dwarf_Attribute attrib = atlist[i]; |
614 | | |
615 | 260k | res = dwarf_whatattr(attrib, &atr, errp); |
616 | 260k | if (res != DW_DLV_OK) { |
617 | 0 | dealloc_rest_of_list(dbg, atlist, atcount, i); |
618 | 0 | return res; |
619 | 0 | } |
620 | 260k | if (atr == DW_AT_ranges) { |
621 | 84.5k | int res2 = 0; |
622 | 84.5k | int res4 = 0; |
623 | 84.5k | Dwarf_Off ret_offset = 0; |
624 | 84.5k | int has_low_hi = FALSE; |
625 | 84.5k | Dwarf_Addr low = 0; |
626 | 84.5k | Dwarf_Addr high = 0; |
627 | | |
628 | 84.5k | res2 = dwarf_global_formref(attrib, &ret_offset, errp); |
629 | 84.5k | if (res2 != DW_DLV_OK) { |
630 | 78.1k | dealloc_rest_of_list(dbg, atlist, atcount, i); |
631 | 78.1k | return res2; |
632 | 78.1k | } |
633 | 6.42k | td->td_ranges_offset = ret_offset + td->td_cu_ranges_base; |
634 | 6.42k | res4 = check_subprog_ranges_for_match(dbg, die, td, &has_low_hi, &low, |
635 | 6.42k | &high, errp); |
636 | 6.42k | if (res4 == DW_DLV_OK) { |
637 | 431 | continue; |
638 | 431 | } |
639 | 5.99k | if (res4 == DW_DLV_NO_ENTRY) { |
640 | 5.90k | continue; |
641 | 5.90k | } |
642 | 85 | if (res4 == FOUND_SUBPROG) { |
643 | 70 | td->td_subprog_lowpc = lowpc; |
644 | 70 | td->td_subprog_highpc = highpc; |
645 | 70 | td->td_subprog_haslowhighpc = has_low_hi; |
646 | 70 | finalres = FOUND_SUBPROG; |
647 | 70 | continue; |
648 | 70 | } |
649 | 15 | dealloc_rest_of_list(dbg, atlist, atcount, i); |
650 | 15 | return res4; |
651 | 176k | } else if (atr == DW_AT_decl_file) { |
652 | 7.09k | int res5 = 0; |
653 | 7.09k | Dwarf_Unsigned file_index = 0; |
654 | | |
655 | 7.09k | res5 = dwarf_formudata(attrib, &file_index, errp); |
656 | 7.09k | if (res5 != DW_DLV_OK) { |
657 | 74 | dealloc_rest_of_list(dbg, atlist, atcount, i); |
658 | 74 | return res5; |
659 | 74 | } |
660 | 7.02k | td->td_subprog_fileindex = file_index; |
661 | 7.02k | } |
662 | 176k | dwarf_dealloc(dbg, attrib, DW_DLA_ATTR); |
663 | 176k | } |
664 | 23.7k | dwarf_dealloc(dbg, atlist, DW_DLA_LIST); |
665 | 23.7k | } |
666 | 0 | return finalres; |
667 | 101k | } |
668 | | |
669 | | static int check_comp_dir(Dwarf_Debug dbg, Dwarf_Die die, |
670 | 13.5k | struct target_data_s *td, Dwarf_Error *errp) { |
671 | 13.5k | int res = 0; |
672 | 13.5k | int finalres = DW_DLV_NO_ENTRY; |
673 | 13.5k | int have_pc_range = FALSE; |
674 | 13.5k | Dwarf_Addr lowpc = 0; |
675 | 13.5k | Dwarf_Addr highpc = 0; |
676 | 13.5k | Dwarf_Off real_ranges_offset = 0; |
677 | 13.5k | int rdone = FALSE; |
678 | | |
679 | 13.5k | res = getlowhighpc(die, &have_pc_range, &lowpc, &highpc, errp); |
680 | 13.5k | if (res == DW_DLV_OK) { |
681 | 1.74k | if (have_pc_range) { |
682 | 1.74k | if (td->td_target_pc < lowpc || td->td_target_pc >= highpc) { |
683 | 542 | res = NOT_THIS_CU; |
684 | 1.20k | } else { |
685 | 1.20k | td->td_cu_lowpc = lowpc; |
686 | 1.20k | td->td_cu_highpc = highpc; |
687 | 1.20k | res = IN_THIS_CU; |
688 | 1.20k | } |
689 | 1.74k | } |
690 | 1.74k | } |
691 | 13.5k | finalres = res; |
692 | 13.5k | { |
693 | 13.5k | Dwarf_Signed atcount = 0; |
694 | 13.5k | Dwarf_Attribute *atlist = 0; |
695 | 13.5k | Dwarf_Signed j = 0; |
696 | 13.5k | int alres = 0; |
697 | | |
698 | 13.5k | alres = dwarf_attrlist(die, &atlist, &atcount, errp); |
699 | 13.5k | if (alres != DW_DLV_OK) { |
700 | 1.92k | return alres; |
701 | 1.92k | } |
702 | 61.3k | for (j = 0; j < atcount; ++j) { |
703 | 49.9k | Dwarf_Half atr = 0; |
704 | 49.9k | Dwarf_Attribute attrib = atlist[j]; |
705 | 49.9k | int resb = 0; |
706 | | |
707 | 49.9k | resb = dwarf_whatattr(attrib, &atr, errp); |
708 | 49.9k | if (resb != DW_DLV_OK) { |
709 | 0 | dwarf_dealloc(dbg, atlist, DW_DLA_LIST); |
710 | 0 | return resb; |
711 | 0 | } |
712 | 49.9k | if (atr == DW_AT_name) { |
713 | 9.52k | char *name = 0; |
714 | 9.52k | resb = dwarf_formstring(attrib, &name, errp); |
715 | 9.52k | if (resb == DW_DLV_OK) { |
716 | 362 | td->td_cu_name = name; |
717 | 362 | } |
718 | 40.4k | } else if (atr == DW_AT_comp_dir) { |
719 | 5.12k | char *name = 0; |
720 | 5.12k | resb = dwarf_formstring(attrib, &name, errp); |
721 | 5.12k | if (resb == DW_DLV_OK) { |
722 | 132 | td->td_cu_comp_dir = name; |
723 | 132 | } |
724 | 35.3k | } else if (atr == DW_AT_rnglists_base || atr == DW_AT_GNU_ranges_base) { |
725 | 1.00k | Dwarf_Off rbase = 0; |
726 | | |
727 | 1.00k | resb = dwarf_global_formref(attrib, &rbase, errp); |
728 | 1.00k | if (resb != DW_DLV_OK) { |
729 | 154 | dwarf_dealloc(dbg, atlist, DW_DLA_LIST); |
730 | 154 | return resb; |
731 | 154 | } |
732 | 855 | td->td_cu_ranges_base = rbase; |
733 | 34.3k | } else if (atr == DW_AT_ranges) { |
734 | | /* we have actual ranges. */ |
735 | 1.60k | Dwarf_Off rbase = 0; |
736 | | |
737 | 1.60k | resb = dwarf_global_formref(attrib, &rbase, errp); |
738 | 1.60k | if (resb != DW_DLV_OK) { |
739 | 63 | dwarf_dealloc(dbg, atlist, DW_DLA_LIST); |
740 | 63 | return resb; |
741 | 63 | } |
742 | 1.53k | real_ranges_offset = rbase; |
743 | 1.53k | rdone = TRUE; |
744 | 1.53k | } |
745 | 49.7k | dwarf_dealloc(dbg, attrib, DW_DLA_ATTR); |
746 | 49.7k | } |
747 | 11.3k | dwarf_dealloc(dbg, atlist, DW_DLA_LIST); |
748 | 11.3k | } |
749 | 11.3k | if (rdone) { |
750 | 1.53k | int resr = 0; |
751 | 1.53k | Dwarf_Ranges *ranges = 0; |
752 | 1.53k | Dwarf_Signed ranges_count = 0; |
753 | 1.53k | Dwarf_Unsigned byte_count = 0; |
754 | 1.53k | Dwarf_Off actualoffset = 0; |
755 | 1.53k | Dwarf_Signed k = 0; |
756 | 1.53k | int done = FALSE; |
757 | | |
758 | 1.53k | resr = dwarf_get_ranges_b(dbg, real_ranges_offset, die, &actualoffset, |
759 | 1.53k | &ranges, &ranges_count, &byte_count, errp); |
760 | 1.53k | if (resr != DW_DLV_OK) { |
761 | 740 | return res; |
762 | 740 | } |
763 | 8.91k | for (k = 0; k < ranges_count && !done; ++k) { |
764 | 8.12k | Dwarf_Ranges *cur = ranges + k; |
765 | 8.12k | Dwarf_Addr lowpcr = 0; |
766 | 8.12k | Dwarf_Addr highpcr = 0; |
767 | 8.12k | Dwarf_Addr baseaddr = td->td_cu_ranges_base; |
768 | | |
769 | 8.12k | switch (cur->dwr_type) { |
770 | 7.66k | case DW_RANGES_ENTRY: |
771 | 7.66k | lowpc = cur->dwr_addr1 + baseaddr; |
772 | 7.66k | highpc = cur->dwr_addr2 + baseaddr; |
773 | 7.66k | if (td->td_target_pc < lowpc || td->td_target_pc >= highpc) { |
774 | 7.28k | break; |
775 | 7.28k | } |
776 | 379 | td->td_cu_lowpc = lowpcr; |
777 | 379 | td->td_cu_highpc = highpcr; |
778 | 379 | td->td_cu_haslowhighpc = TRUE; |
779 | 379 | done = TRUE; |
780 | 379 | finalres = IN_THIS_CU; |
781 | 379 | break; |
782 | 125 | case DW_RANGES_ADDRESS_SELECTION: |
783 | 125 | baseaddr = cur->dwr_addr2; |
784 | 125 | break; |
785 | 330 | case DW_RANGES_END: |
786 | 330 | break; |
787 | 0 | default: |
788 | 0 | return DW_DLV_ERROR; |
789 | 8.12k | } |
790 | 8.12k | } |
791 | 797 | dwarf_dealloc_ranges(dbg, ranges, ranges_count); |
792 | 797 | } |
793 | 10.6k | return finalres; |
794 | 11.3k | } |
795 | | |
796 | | static int examine_die_data(Dwarf_Debug dbg, int is_info, Dwarf_Die die, |
797 | | int level, struct target_data_s *td, |
798 | 9.90M | Dwarf_Error *errp) { |
799 | 9.90M | Dwarf_Half tag = 0; |
800 | 9.90M | int res = 0; |
801 | | |
802 | 9.90M | res = dwarf_tag(die, &tag, errp); |
803 | 9.90M | if (res != DW_DLV_OK) { |
804 | 0 | return res; |
805 | 0 | } |
806 | 9.90M | if (tag == DW_TAG_subprogram || tag == DW_TAG_inlined_subroutine) { |
807 | 104k | int have_pc_range = 0; |
808 | 104k | Dwarf_Addr lowpc = 0; |
809 | 104k | Dwarf_Addr highpc = 0; |
810 | | |
811 | 104k | res = check_subprog_details(dbg, is_info, die, td, &have_pc_range, &lowpc, |
812 | 104k | &highpc, errp); |
813 | 104k | if (res == FOUND_SUBPROG) { |
814 | 1.24k | td->td_subprog_die = die; |
815 | 1.24k | return res; |
816 | 103k | } else if (res == DW_DLV_ERROR) { |
817 | 562 | return res; |
818 | 102k | } else if (res == DW_DLV_NO_ENTRY) { |
819 | | /* impossible? */ |
820 | 80.1k | return res; |
821 | 80.1k | } else if (res == NOT_THIS_CU) { |
822 | | /* impossible */ |
823 | 0 | return res; |
824 | 22.5k | } else if (res == IN_THIS_CU) { |
825 | | /* impossible */ |
826 | 0 | return res; |
827 | 22.5k | } else { |
828 | | /* DW_DLV_OK */ |
829 | 22.5k | } |
830 | 22.5k | return DW_DLV_OK; |
831 | 9.80M | } else if (tag == DW_TAG_compile_unit || tag == DW_TAG_partial_unit || |
832 | 9.78M | tag == DW_TAG_type_unit) { |
833 | | |
834 | 4.67M | if (level) { |
835 | 4.66M | return NOT_THIS_CU; |
836 | 4.66M | } |
837 | 13.5k | res = check_comp_dir(dbg, die, td, errp); |
838 | 13.5k | return res; |
839 | 4.67M | } |
840 | 5.12M | return DW_DLV_OK; |
841 | 9.90M | } |