Coverage Report

Created: 2026-06-10 06:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
43.8k
#define TRUE 1
32
236k
#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
449k
#define NOT_THIS_CU 10
73
261k
#define IN_THIS_CU 11
74
531k
#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
16.2k
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
95
16.2k
  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
16.2k
  sprintf(filename, "/tmp/libfuzzer.%d", getpid());
105
16.2k
#endif
106
16.2k
  FILE *fp = fopen(filename, "wb");
107
16.2k
  if (!fp) {
108
0
    printf("FAIL libfuzzer cannot open temp as writeable %s\n",
109
0
        filename);
110
0
    return 0;
111
0
  }
112
16.2k
  fwrite(data, size, 1, fp);
113
16.2k
  fclose(fp);
114
115
16.2k
  Dwarf_Debug dbg = 0;
116
16.2k
  Dwarf_Error error = 0;
117
16.2k
  Dwarf_Handler errhand = 0;
118
16.2k
  Dwarf_Ptr errarg = 0;
119
16.2k
  int i = 0;
120
16.2k
  Dwarf_Unsigned target_pc = 0x1000;
121
16.2k
#define PATH_LEN 2000
122
16.2k
  char real_path[PATH_LEN];
123
16.2k
  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
16.2k
  memset(&target_data,0,sizeof(target_data));
129
16.2k
  int res =
130
16.2k
      dwarf_init_path(filename, 0, 0, DW_GROUPNUMBER_ANY, 0, 0, &dbg, &error);
131
16.2k
  if (res == DW_DLV_ERROR) {
132
5.07k
    dwarf_dealloc_error(dbg, error);
133
5.07k
    dwarf_finish(dbg);
134
11.1k
  } else {
135
11.1k
    res = look_for_our_target(dbg, &target_data, &error);
136
11.1k
    res = dwarf_finish(dbg);
137
11.1k
  }
138
139
16.2k
  unlink(filename);
140
16.2k
  return 0;
141
16.2k
}
142
143
static int read_line_data(Dwarf_Debug dbg, struct target_data_s *td,
144
1.37k
                          Dwarf_Error *errp) {
145
1.37k
  int res = 0;
146
1.37k
  Dwarf_Unsigned line_version = 0;
147
1.37k
  Dwarf_Small table_type = 0;
148
1.37k
  Dwarf_Line_Context line_context = 0;
149
1.37k
  Dwarf_Signed i = 0;
150
1.37k
  Dwarf_Signed baseindex = 0;
151
1.37k
  Dwarf_Signed endindex = 0;
152
1.37k
  Dwarf_Signed file_count = 0;
153
1.37k
  Dwarf_Unsigned dirindex = 0;
154
155
1.37k
  (void)dbg;
156
1.37k
  res = dwarf_srclines_b(td->td_cu_die, &line_version, &table_type,
157
1.37k
                         &line_context, errp);
158
1.37k
  if (res != DW_DLV_OK) {
159
1.04k
    return res;
160
1.04k
  }
161
332
  if (table_type == 0) {
162
10
    int sres = 0;
163
164
10
    sres = dwarf_srclines_files_indexes(line_context, &baseindex, &file_count,
165
10
                                        &endindex, errp);
166
10
    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
124
    for (i = baseindex; i < endindex; i++) {
172
114
      Dwarf_Unsigned modtime = 0;
173
114
      Dwarf_Unsigned flength = 0;
174
114
      Dwarf_Form_Data16 *md5data = 0;
175
114
      int vres = 0;
176
114
      const char *name = 0;
177
178
114
      vres = dwarf_srclines_files_data_b(line_context, i, &name, &dirindex,
179
114
                                         &modtime, &flength, &md5data, errp);
180
114
      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
114
    }
186
10
    dwarf_srclines_dealloc_b(line_context);
187
10
    return DW_DLV_OK;
188
322
  } else if (table_type == 1) {
189
319
    const char *dir_name = 0;
190
319
    int sres = 0;
191
319
    Dwarf_Line *linebuf = 0;
192
319
    Dwarf_Signed linecount = 0;
193
319
    Dwarf_Signed dir_count = 0;
194
319
    Dwarf_Addr prev_lineaddr = 0;
195
319
    Dwarf_Unsigned prev_lineno = 0;
196
319
    char *prev_linesrcfile = 0;
197
198
319
    sres = dwarf_srclines_files_indexes(line_context, &baseindex, &file_count,
199
319
                                        &endindex, errp);
200
319
    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
24.4k
    for (i = baseindex; i < endindex; i++) {
206
24.1k
      Dwarf_Unsigned dirindexb = 0;
207
24.1k
      Dwarf_Unsigned modtime = 0;
208
24.1k
      Dwarf_Unsigned flength = 0;
209
24.1k
      Dwarf_Form_Data16 *md5data = 0;
210
24.1k
      int vres = 0;
211
24.1k
      const char *name = 0;
212
213
24.1k
      vres = dwarf_srclines_files_data_b(line_context, i, &name, &dirindexb,
214
24.1k
                                         &modtime, &flength, &md5data, errp);
215
24.1k
      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
24.1k
    }
221
319
    sres = dwarf_srclines_include_dir_count(line_context, &dir_count, errp);
222
319
    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
2.96k
    for (i = 1; i <= dir_count; ++i) {
229
2.64k
      dir_name = 0;
230
2.64k
      sres = dwarf_srclines_include_dir_data(line_context, i, &dir_name, errp);
231
2.64k
      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
2.64k
    }
237
238
319
    sres = dwarf_srclines_from_linecontext(line_context, &linebuf, &linecount,
239
319
                                           errp);
240
319
    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
479k
    for (i = 0; i < linecount; ++i) {
246
479k
      Dwarf_Addr lineaddr = 0;
247
479k
      Dwarf_Unsigned filenum = 0;
248
479k
      Dwarf_Unsigned lineno = 0;
249
479k
      char *linesrcfile = 0;
250
251
479k
      sres = dwarf_lineno(linebuf[i], &lineno, errp);
252
479k
      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
479k
      sres = dwarf_line_srcfileno(linebuf[i], &filenum, errp);
259
479k
      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
479k
      if (filenum) {
266
471k
        filenum -= 1;
267
471k
      }
268
479k
      sres = dwarf_lineaddr(linebuf[i], &lineaddr, errp);
269
479k
      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
479k
      sres = dwarf_linesrc(linebuf[i], &linesrcfile, errp);
276
479k
      if (sres == DW_DLV_ERROR) {
277
164
        if (prev_linesrcfile) {
278
154
          dwarf_dealloc(dbg, prev_linesrcfile, DW_DLA_STRING);
279
154
        }
280
164
        return sres;
281
164
      }
282
479k
      if (lineaddr > td->td_target_pc) {
283
82
        td->td_subprog_lineaddr = prev_lineaddr;
284
82
        td->td_subprog_lineno = prev_lineno;
285
82
        td->td_subprog_srcfile = prev_linesrcfile;
286
82
        dwarf_dealloc(dbg, linesrcfile, DW_DLA_STRING);
287
82
        return DW_DLV_OK;
288
82
      }
289
479k
      prev_lineaddr = lineaddr;
290
479k
      prev_lineno = lineno;
291
479k
      if (prev_linesrcfile) {
292
470k
        dwarf_dealloc(dbg, prev_linesrcfile, DW_DLA_STRING);
293
470k
      }
294
479k
      prev_linesrcfile = linesrcfile;
295
479k
    }
296
73
    td->td_subprog_lineaddr = prev_lineaddr;
297
73
    td->td_subprog_lineno = prev_lineno;
298
73
    td->td_subprog_srcfile = prev_linesrcfile;
299
73
    dwarf_srclines_dealloc_b(line_context);
300
73
    return DW_DLV_OK;
301
319
  }
302
3
  return DW_DLV_ERROR;
303
332
}
304
305
static int look_for_our_target(Dwarf_Debug dbg, struct target_data_s *td,
306
11.1k
                               Dwarf_Error *errp) {
307
11.1k
  Dwarf_Unsigned cu_header_length = 0;
308
11.1k
  Dwarf_Unsigned abbrev_offset = 0;
309
11.1k
  Dwarf_Half address_size = 0;
310
11.1k
  Dwarf_Half version_stamp = 0;
311
11.1k
  Dwarf_Half offset_size = 0;
312
11.1k
  Dwarf_Half extension_size = 0;
313
11.1k
  Dwarf_Unsigned typeoffset = 0;
314
11.1k
  Dwarf_Half header_cu_type = unittype;
315
11.1k
  Dwarf_Bool is_info = g_is_info;
316
11.1k
  int cu_number = 0;
317
318
11.1k
  for (;; ++cu_number) {
319
11.1k
    Dwarf_Die no_die = 0;
320
11.1k
    Dwarf_Die cu_die = 0;
321
11.1k
    int res = DW_DLV_ERROR;
322
11.1k
    Dwarf_Sig8 signature;
323
324
11.1k
    memset(&signature, 0, sizeof(signature));
325
11.1k
    res = dwarf_next_cu_header_d(dbg, is_info, &cu_header_length,
326
11.1k
                                 &version_stamp, &abbrev_offset, &address_size,
327
11.1k
                                 &offset_size, &extension_size, &signature,
328
11.1k
                                 &typeoffset, 0, &header_cu_type, errp);
329
11.1k
    if (res == DW_DLV_ERROR) {
330
4.47k
      if (errp) {
331
4.47k
        char *em = dwarf_errmsg(*errp);
332
4.47k
      }
333
4.47k
      return DW_DLV_NO_ENTRY;
334
4.47k
    }
335
6.70k
    if (res == DW_DLV_NO_ENTRY) {
336
521
      return DW_DLV_NO_ENTRY;
337
521
    }
338
6.18k
    cu_version_stamp = version_stamp;
339
6.18k
    cu_offset_size = offset_size;
340
6.18k
    res = dwarf_siblingof_b(dbg, no_die, is_info, &cu_die, errp);
341
6.18k
    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
6.18k
    if (res == DW_DLV_NO_ENTRY) {
348
508
      return res;
349
508
    }
350
351
5.67k
    td->td_cu_die = cu_die;
352
5.67k
    res = get_die_and_siblings(dbg, cu_die, is_info, 0, cu_number, td, errp);
353
5.67k
    if (res == FOUND_SUBPROG) {
354
1.37k
      read_line_data(dbg, td, errp);
355
1.37k
      if (td->td_reportallfound) {
356
0
        return res;
357
0
      }
358
1.37k
      return res;
359
4.30k
    } 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.30k
    } else if (res == DW_DLV_ERROR) {
365
2.08k
      if (errp) {
366
2.08k
        char *em = dwarf_errmsg(*errp);
367
2.08k
      }
368
2.08k
      return DW_DLV_ERROR;
369
2.08k
    }
370
2.22k
    return DW_DLV_NO_ENTRY;
371
5.67k
  }
372
11.1k
}
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
193k
                                struct target_data_s *td, Dwarf_Error *errp) {
377
193k
  int res = DW_DLV_ERROR;
378
193k
  Dwarf_Die cur_die = in_die;
379
193k
  Dwarf_Die child = 0;
380
381
193k
  td->td_cu_number = cu_number;
382
193k
  res = examine_die_data(dbg, is_info, in_die, in_level, td, errp);
383
193k
  if (res == DW_DLV_ERROR) {
384
358
    return res;
385
358
  }
386
192k
  if (res == DW_DLV_NO_ENTRY) {
387
7.41k
    return res;
388
7.41k
  }
389
185k
  if (res == NOT_THIS_CU) {
390
27
    return res;
391
185k
  } else if (res == FOUND_SUBPROG) {
392
205
    return res;
393
185k
  } else {
394
185k
  }
395
396
6.47M
  for (;;) {
397
6.47M
    Dwarf_Die sib_die = 0;
398
6.47M
    res = dwarf_child(cur_die, &child, errp);
399
6.47M
    if (res == DW_DLV_ERROR) {
400
580
      return res;
401
580
    }
402
6.47M
    if (res == DW_DLV_OK) {
403
187k
      int res2 = 0;
404
405
187k
      res2 = get_die_and_siblings(dbg, child, is_info, in_level + 1, cu_number,
406
187k
                                  td, errp);
407
187k
      if (child != td->td_cu_die && child != td->td_subprog_die) {
408
181k
        dwarf_dealloc(dbg, child, DW_DLA_DIE);
409
181k
      }
410
187k
      if (res2 == FOUND_SUBPROG) {
411
3.00k
        return res2;
412
184k
      } else if (res2 == IN_THIS_CU) {
413
184k
      } else if (res2 == NOT_THIS_CU) {
414
270
        return res2;
415
184k
      } else if (res2 == DW_DLV_ERROR) {
416
39.6k
        return res2;
417
144k
      } else if (res2 == DW_DLV_NO_ENTRY) {
418
137k
      } else { /* DW_DLV_OK */
419
137k
      }
420
144k
      child = 0;
421
144k
    }
422
6.42M
    res = dwarf_siblingof_b(dbg, cur_die, is_info, &sib_die, errp);
423
6.42M
    if (res == DW_DLV_ERROR) {
424
1.01k
      if (errp) {
425
1.01k
          char *em = dwarf_errmsg(*errp);
426
1.01k
      }
427
1.01k
      return res;
428
1.01k
    }
429
6.42M
    if (res == DW_DLV_NO_ENTRY) {
430
139k
      break;
431
139k
    }
432
6.28M
    if (cur_die != in_die) {
433
6.16M
      if (child != td->td_cu_die && child != td->td_subprog_die) {
434
1.94M
        dwarf_dealloc(dbg, cur_die, DW_DLA_DIE);
435
1.94M
      }
436
6.16M
      cur_die = 0;
437
6.16M
    }
438
6.28M
    cur_die = sib_die;
439
6.28M
    res = examine_die_data(dbg, is_info, cur_die, in_level, td, errp);
440
6.28M
    if (res == DW_DLV_ERROR) {
441
131
      return res;
442
6.28M
    } else if (res == DW_DLV_OK) {
443
6.23M
    } else if (res == FOUND_SUBPROG) {
444
1.17k
      return res;
445
51.0k
    } else if (res == NOT_THIS_CU) {
446
46.8k
    } else if (res == IN_THIS_CU) {
447
46.1k
    } else {
448
46.1k
    }
449
6.28M
  }
450
139k
  return DW_DLV_OK;
451
185k
}
452
453
static void dealloc_rest_of_list(Dwarf_Debug dbg, Dwarf_Attribute *attrbuf,
454
39.8k
                                 Dwarf_Signed attrcount, Dwarf_Signed i) {
455
240k
  for (; i < attrcount; ++i) {
456
201k
    dwarf_dealloc_attribute(attrbuf[i]);
457
201k
  }
458
39.8k
  dwarf_dealloc(dbg, attrbuf, DW_DLA_LIST);
459
39.8k
}
460
461
static int getlowhighpc(Dwarf_Die die, int *have_pc_range,
462
                        Dwarf_Addr *lowpc_out, Dwarf_Addr *highpc_out,
463
82.2k
                        Dwarf_Error *error) {
464
82.2k
  Dwarf_Addr hipc = 0;
465
82.2k
  int res = 0;
466
82.2k
  Dwarf_Half form = 0;
467
82.2k
  enum Dwarf_Form_Class formclass = 0;
468
469
82.2k
  *have_pc_range = FALSE;
470
82.2k
  res = dwarf_lowpc(die, lowpc_out, error);
471
82.2k
  if (res == DW_DLV_OK) {
472
46.0k
    res = dwarf_highpc_b(die, &hipc, &form, &formclass, error);
473
46.0k
    if (res == DW_DLV_OK) {
474
39.6k
      if (formclass == DW_FORM_CLASS_CONSTANT) {
475
11.8k
        hipc += *lowpc_out;
476
11.8k
      }
477
39.6k
      *highpc_out = hipc;
478
39.6k
      *have_pc_range = TRUE;
479
39.6k
      return DW_DLV_OK;
480
39.6k
    }
481
46.0k
  }
482
42.5k
  return DW_DLV_NO_ENTRY;
483
82.2k
}
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
8.10k
                                          Dwarf_Error *errp) {
491
8.10k
  int res = 0;
492
8.10k
  Dwarf_Ranges *ranges;
493
8.10k
  Dwarf_Signed ranges_count;
494
8.10k
  Dwarf_Unsigned byte_count;
495
8.10k
  Dwarf_Signed i = 0;
496
8.10k
  Dwarf_Addr baseaddr = 0;
497
8.10k
  Dwarf_Off actualoffset = 0;
498
8.10k
  int done = FALSE;
499
500
8.10k
  res = dwarf_get_ranges_b(dbg, td->td_ranges_offset, die, &actualoffset,
501
8.10k
                           &ranges, &ranges_count, &byte_count, errp);
502
8.10k
  if (res != DW_DLV_OK) {
503
7.12k
    return res;
504
7.12k
  }
505
19.2k
  for (i = 0; i < ranges_count && !done; ++i) {
506
18.2k
    Dwarf_Ranges *cur = ranges + i;
507
18.2k
    Dwarf_Addr lowpc = 0;
508
18.2k
    Dwarf_Addr highpc = 0;
509
18.2k
    switch (cur->dwr_type) {
510
17.2k
    case DW_RANGES_ENTRY:
511
17.2k
      lowpc = cur->dwr_addr1 + baseaddr;
512
17.2k
      highpc = cur->dwr_addr2 + baseaddr;
513
17.2k
      if (td->td_target_pc < lowpc || td->td_target_pc >= highpc) {
514
17.1k
        break;
515
17.1k
      }
516
67
      *lowpc_out = lowpc;
517
67
      *highpc_out = highpc;
518
67
      *have_pc_range = TRUE;
519
67
      done = TRUE;
520
67
      res = FOUND_SUBPROG;
521
67
      break;
522
517
    case DW_RANGES_ADDRESS_SELECTION:
523
517
      baseaddr = cur->dwr_addr2;
524
517
      break;
525
513
    case DW_RANGES_END:
526
513
      break;
527
0
    default:
528
0
      return DW_DLV_ERROR;
529
18.2k
    }
530
18.2k
  }
531
984
  dwarf_dealloc_ranges(dbg, ranges, ranges_count);
532
984
  return res;
533
984
}
534
535
static int get_name_from_abstract_origin(Dwarf_Debug dbg, int is_info,
536
                                         Dwarf_Die die, char **name,
537
31.8k
                                         Dwarf_Error *errp) {
538
31.8k
  int res = 0;
539
31.8k
  Dwarf_Die abrootdie = 0;
540
31.8k
  Dwarf_Attribute ab_attr = 0;
541
31.8k
  Dwarf_Off ab_offset = 0;
542
543
31.8k
  res = dwarf_attr(die, DW_AT_abstract_origin, &ab_attr, errp);
544
31.8k
  if (res != DW_DLV_OK) {
545
1.57k
    return res;
546
1.57k
  }
547
548
30.3k
  res = dwarf_global_formref(ab_attr, &ab_offset, errp);
549
30.3k
  if (res != DW_DLV_OK) {
550
12.6k
    dwarf_dealloc(dbg, ab_attr, DW_DLA_ATTR);
551
12.6k
    return res;
552
12.6k
  }
553
554
17.6k
  dwarf_dealloc(dbg, ab_attr, DW_DLA_ATTR);
555
17.6k
  res = dwarf_offdie_b(dbg, ab_offset, is_info, &abrootdie, errp);
556
17.6k
  if (res != DW_DLV_OK) {
557
12.5k
    return res;
558
12.5k
  }
559
5.09k
  res = dwarf_diename(abrootdie, name, errp);
560
5.09k
  dwarf_dealloc_die(abrootdie);
561
5.09k
  return res;
562
17.6k
}
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
68.8k
                                 Dwarf_Addr *highpc_out, Dwarf_Error *errp) {
568
68.8k
  int res = 0;
569
68.8k
  Dwarf_Addr lowpc = 0;
570
68.8k
  Dwarf_Addr highpc = 0;
571
68.8k
  int finalres = 0;
572
68.8k
  int have_pc_range = FALSE;
573
574
68.8k
  res = getlowhighpc(die, &have_pc_range, &lowpc, &highpc, errp);
575
68.8k
  if (res == DW_DLV_OK) {
576
37.7k
    if (have_pc_range) {
577
37.7k
      int res2 = DW_DLV_OK;
578
37.7k
      char *name = 0;
579
580
37.7k
      if (td->td_target_pc < lowpc || td->td_target_pc >= highpc) {
581
5.71k
        finalres = DW_DLV_OK;
582
31.9k
      } else {
583
31.9k
        td->td_subprog_die = die;
584
31.9k
        td->td_subprog_lowpc = lowpc;
585
31.9k
        *lowpc_out = lowpc;
586
31.9k
        *highpc_out = highpc;
587
31.9k
        *have_pc_range_out = have_pc_range;
588
31.9k
        td->td_subprog_highpc = highpc;
589
31.9k
        td->td_subprog_haslowhighpc = have_pc_range;
590
31.9k
        res2 = dwarf_diename(die, &name, errp);
591
31.9k
        if (res2 == DW_DLV_OK) {
592
110
          td->td_subprog_name = name;
593
31.8k
        } else {
594
31.8k
          get_name_from_abstract_origin(dbg, is_info, die, &name, errp);
595
31.8k
        }
596
31.9k
        td->td_subprog_name = name;
597
31.9k
        name = 0;
598
31.9k
        finalres = FOUND_SUBPROG;
599
31.9k
      }
600
37.7k
    }
601
37.7k
  }
602
68.8k
  {
603
68.8k
    Dwarf_Signed i = 0;
604
68.8k
    Dwarf_Signed atcount = 0;
605
68.8k
    Dwarf_Attribute *atlist = 0;
606
607
68.8k
    res = dwarf_attrlist(die, &atlist, &atcount, errp);
608
68.8k
    if (res != DW_DLV_OK) {
609
3.40k
      return res;
610
3.40k
    }
611
216k
    for (i = 0; i < atcount; ++i) {
612
191k
      Dwarf_Half atr = 0;
613
191k
      Dwarf_Attribute attrib = atlist[i];
614
615
191k
      res = dwarf_whatattr(attrib, &atr, errp);
616
191k
      if (res != DW_DLV_OK) {
617
0
        dealloc_rest_of_list(dbg, atlist, atcount, i);
618
0
        return res;
619
0
      }
620
191k
      if (atr == DW_AT_ranges) {
621
47.9k
        int res2 = 0;
622
47.9k
        int res4 = 0;
623
47.9k
        Dwarf_Off ret_offset = 0;
624
47.9k
        int has_low_hi = FALSE;
625
47.9k
        Dwarf_Addr low = 0;
626
47.9k
        Dwarf_Addr high = 0;
627
628
47.9k
        res2 = dwarf_global_formref(attrib, &ret_offset, errp);
629
47.9k
        if (res2 != DW_DLV_OK) {
630
39.8k
          dealloc_rest_of_list(dbg, atlist, atcount, i);
631
39.8k
          return res2;
632
39.8k
        }
633
8.10k
        td->td_ranges_offset = ret_offset + td->td_cu_ranges_base;
634
8.10k
        res4 = check_subprog_ranges_for_match(dbg, die, td, &has_low_hi, &low,
635
8.10k
                                              &high, errp);
636
8.10k
        if (res4 == DW_DLV_OK) {
637
917
          continue;
638
917
        }
639
7.18k
        if (res4 == DW_DLV_NO_ENTRY) {
640
7.09k
          continue;
641
7.09k
        }
642
92
        if (res4 == FOUND_SUBPROG) {
643
67
          td->td_subprog_lowpc = lowpc;
644
67
          td->td_subprog_highpc = highpc;
645
67
          td->td_subprog_haslowhighpc = has_low_hi;
646
67
          finalres = FOUND_SUBPROG;
647
67
          continue;
648
67
        }
649
25
        dealloc_rest_of_list(dbg, atlist, atcount, i);
650
25
        return res4;
651
143k
      } else if (atr == DW_AT_decl_file) {
652
6.84k
        int res5 = 0;
653
6.84k
        Dwarf_Unsigned file_index = 0;
654
655
6.84k
        res5 = dwarf_formudata(attrib, &file_index, errp);
656
6.84k
        if (res5 != DW_DLV_OK) {
657
14
          dealloc_rest_of_list(dbg, atlist, atcount, i);
658
14
          return res5;
659
14
        }
660
6.82k
        td->td_subprog_fileindex = file_index;
661
6.82k
      }
662
143k
      dwarf_dealloc(dbg, attrib, DW_DLA_ATTR);
663
143k
    }
664
25.6k
    dwarf_dealloc(dbg, atlist, DW_DLA_LIST);
665
25.6k
  }
666
0
  return finalres;
667
65.4k
}
668
669
static int check_comp_dir(Dwarf_Debug dbg, Dwarf_Die die,
670
13.4k
                          struct target_data_s *td, Dwarf_Error *errp) {
671
13.4k
  int res = 0;
672
13.4k
  int finalres = DW_DLV_NO_ENTRY;
673
13.4k
  int have_pc_range = FALSE;
674
13.4k
  Dwarf_Addr lowpc = 0;
675
13.4k
  Dwarf_Addr highpc = 0;
676
13.4k
  Dwarf_Off real_ranges_offset = 0;
677
13.4k
  int rdone = FALSE;
678
679
13.4k
  res = getlowhighpc(die, &have_pc_range, &lowpc, &highpc, errp);
680
13.4k
  if (res == DW_DLV_OK) {
681
1.98k
    if (have_pc_range) {
682
1.98k
      if (td->td_target_pc < lowpc || td->td_target_pc >= highpc) {
683
514
        res = NOT_THIS_CU;
684
1.47k
      } else {
685
1.47k
        td->td_cu_lowpc = lowpc;
686
1.47k
        td->td_cu_highpc = highpc;
687
1.47k
        res = IN_THIS_CU;
688
1.47k
      }
689
1.98k
    }
690
1.98k
  }
691
13.4k
  finalres = res;
692
13.4k
  {
693
13.4k
    Dwarf_Signed atcount = 0;
694
13.4k
    Dwarf_Attribute *atlist = 0;
695
13.4k
    Dwarf_Signed j = 0;
696
13.4k
    int alres = 0;
697
698
13.4k
    alres = dwarf_attrlist(die, &atlist, &atcount, errp);
699
13.4k
    if (alres != DW_DLV_OK) {
700
313
      return alres;
701
313
    }
702
74.4k
    for (j = 0; j < atcount; ++j) {
703
61.5k
      Dwarf_Half atr = 0;
704
61.5k
      Dwarf_Attribute attrib = atlist[j];
705
61.5k
      int resb = 0;
706
707
61.5k
      resb = dwarf_whatattr(attrib, &atr, errp);
708
61.5k
      if (resb != DW_DLV_OK) {
709
0
        dwarf_dealloc(dbg, atlist, DW_DLA_LIST);
710
0
        return resb;
711
0
      }
712
61.5k
      if (atr == DW_AT_name) {
713
11.4k
        char *name = 0;
714
11.4k
        resb = dwarf_formstring(attrib, &name, errp);
715
11.4k
        if (resb == DW_DLV_OK) {
716
532
          td->td_cu_name = name;
717
532
        }
718
50.0k
      } else if (atr == DW_AT_comp_dir) {
719
5.67k
        char *name = 0;
720
5.67k
        resb = dwarf_formstring(attrib, &name, errp);
721
5.67k
        if (resb == DW_DLV_OK) {
722
347
          td->td_cu_comp_dir = name;
723
347
        }
724
44.3k
      } else if (atr == DW_AT_rnglists_base || atr == DW_AT_GNU_ranges_base) {
725
1.06k
        Dwarf_Off rbase = 0;
726
727
1.06k
        resb = dwarf_global_formref(attrib, &rbase, errp);
728
1.06k
        if (resb != DW_DLV_OK) {
729
128
          dwarf_dealloc(dbg, atlist, DW_DLA_LIST);
730
128
          return resb;
731
128
        }
732
938
        td->td_cu_ranges_base = rbase;
733
43.3k
      } else if (atr == DW_AT_ranges) {
734
        /* we have actual ranges. */
735
2.84k
        Dwarf_Off rbase = 0;
736
737
2.84k
        resb = dwarf_global_formref(attrib, &rbase, errp);
738
2.84k
        if (resb != DW_DLV_OK) {
739
80
          dwarf_dealloc(dbg, atlist, DW_DLA_LIST);
740
80
          return resb;
741
80
        }
742
2.76k
        real_ranges_offset = rbase;
743
2.76k
        rdone = TRUE;
744
2.76k
      }
745
61.3k
      dwarf_dealloc(dbg, attrib, DW_DLA_ATTR);
746
61.3k
    }
747
12.8k
    dwarf_dealloc(dbg, atlist, DW_DLA_LIST);
748
12.8k
  }
749
12.8k
  if (rdone) {
750
2.76k
    int resr = 0;
751
2.76k
    Dwarf_Ranges *ranges = 0;
752
2.76k
    Dwarf_Signed ranges_count = 0;
753
2.76k
    Dwarf_Unsigned byte_count = 0;
754
2.76k
    Dwarf_Off actualoffset = 0;
755
2.76k
    Dwarf_Signed k = 0;
756
2.76k
    int done = FALSE;
757
758
2.76k
    resr = dwarf_get_ranges_b(dbg, real_ranges_offset, die, &actualoffset,
759
2.76k
                              &ranges, &ranges_count, &byte_count, errp);
760
2.76k
    if (resr != DW_DLV_OK) {
761
1.68k
      return res;
762
1.68k
    }
763
40.0k
    for (k = 0; k < ranges_count && !done; ++k) {
764
39.0k
      Dwarf_Ranges *cur = ranges + k;
765
39.0k
      Dwarf_Addr lowpcr = 0;
766
39.0k
      Dwarf_Addr highpcr = 0;
767
39.0k
      Dwarf_Addr baseaddr = td->td_cu_ranges_base;
768
769
39.0k
      switch (cur->dwr_type) {
770
37.9k
      case DW_RANGES_ENTRY:
771
37.9k
        lowpc = cur->dwr_addr1 + baseaddr;
772
37.9k
        highpc = cur->dwr_addr2 + baseaddr;
773
37.9k
        if (td->td_target_pc < lowpc || td->td_target_pc >= highpc) {
774
37.3k
          break;
775
37.3k
        }
776
640
        td->td_cu_lowpc = lowpcr;
777
640
        td->td_cu_highpc = highpcr;
778
640
        td->td_cu_haslowhighpc = TRUE;
779
640
        done = TRUE;
780
640
        finalres = IN_THIS_CU;
781
640
        break;
782
584
      case DW_RANGES_ADDRESS_SELECTION:
783
584
        baseaddr = cur->dwr_addr2;
784
584
        break;
785
430
      case DW_RANGES_END:
786
430
        break;
787
0
      default:
788
0
        return DW_DLV_ERROR;
789
39.0k
      }
790
39.0k
    }
791
1.08k
    dwarf_dealloc_ranges(dbg, ranges, ranges_count);
792
1.08k
  }
793
11.1k
  return finalres;
794
12.8k
}
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
6.48M
                            Dwarf_Error *errp) {
799
6.48M
  Dwarf_Half tag = 0;
800
6.48M
  int res = 0;
801
802
6.48M
  res = dwarf_tag(die, &tag, errp);
803
6.48M
  if (res != DW_DLV_OK) {
804
0
    return res;
805
0
  }
806
6.48M
  if (tag == DW_TAG_subprogram || tag == DW_TAG_inlined_subroutine) {
807
68.8k
    int have_pc_range = 0;
808
68.8k
    Dwarf_Addr lowpc = 0;
809
68.8k
    Dwarf_Addr highpc = 0;
810
811
68.8k
    res = check_subprog_details(dbg, is_info, die, td, &have_pc_range, &lowpc,
812
68.8k
                                &highpc, errp);
813
68.8k
    if (res == FOUND_SUBPROG) {
814
1.37k
      td->td_subprog_die = die;
815
1.37k
      return res;
816
67.4k
    } else if (res == DW_DLV_ERROR) {
817
363
      return res;
818
67.1k
    } else if (res == DW_DLV_NO_ENTRY) {
819
      /* impossible? */
820
42.8k
      return res;
821
42.8k
    } else if (res == NOT_THIS_CU) {
822
      /* impossible */
823
0
      return res;
824
24.2k
    } else if (res == IN_THIS_CU) {
825
      /* impossible */
826
0
      return res;
827
24.2k
    } else {
828
      /* DW_DLV_OK */
829
24.2k
    }
830
24.2k
    return DW_DLV_OK;
831
6.41M
  } else if (tag == DW_TAG_compile_unit || tag == DW_TAG_partial_unit ||
832
6.39M
             tag == DW_TAG_type_unit) {
833
834
17.0k
    if (level) {
835
3.68k
      return NOT_THIS_CU;
836
3.68k
    }
837
13.4k
    res = check_comp_dir(dbg, die, td, errp);
838
13.4k
    return res;
839
17.0k
  }
840
6.39M
  return DW_DLV_OK;
841
6.48M
}