libdwfl: Sanity check partial core file dyn data read.
[platform/upstream/elfutils.git] / libdw / dwarf_get_units.c
1 /* Iterate through the CU units for a given Dwarf.
2    Copyright (C) 2016, 2017 Red Hat, Inc.
3    This file is part of elfutils.
4
5    This file is free software; you can redistribute it and/or modify
6    it under the terms of either
7
8      * the GNU Lesser General Public License as published by the Free
9        Software Foundation; either version 3 of the License, or (at
10        your option) any later version
11
12    or
13
14      * the GNU General Public License as published by the Free
15        Software Foundation; either version 2 of the License, or (at
16        your option) any later version
17
18    or both in parallel, as here.
19
20    elfutils is distributed in the hope that it will be useful, but
21    WITHOUT ANY WARRANTY; without even the implied warranty of
22    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23    General Public License for more details.
24
25    You should have received copies of the GNU General Public License and
26    the GNU Lesser General Public License along with this program.  If
27    not, see <http://www.gnu.org/licenses/>.  */
28
29
30 #ifdef HAVE_CONFIG_H
31 # include <config.h>
32 #endif
33
34 #include <string.h>
35
36 #include "libdwP.h"
37
38 int
39 dwarf_get_units (Dwarf *dwarf, Dwarf_CU *cu, Dwarf_CU **next_cu,
40                  Dwarf_Half *version, uint8_t *unit_type,
41                  Dwarf_Die *cudie, Dwarf_Die *subdie)
42 {
43   /* Handle existing error.  */
44   if (dwarf == NULL)
45     return -1;
46
47   Dwarf_Off off;
48   bool v4type;
49   if (cu == NULL)
50     {
51       off = 0;
52       v4type = false;
53     }
54   else
55     {
56       off = cu->end;
57       v4type = cu->sec_idx != IDX_debug_info;
58
59       /* Make sure we got a real (not fake) CU.  */
60       if (cu->sec_idx != IDX_debug_info && cu->sec_idx != IDX_debug_types)
61         {
62           __libdw_seterrno (DWARF_E_INVALID_OFFSET);
63           return -1;
64         }
65
66       /* Do we have to switch to the other section, or are we at the end?  */
67       if (! v4type)
68         {
69           if (off >= cu->dbg->sectiondata[IDX_debug_info]->d_size)
70             {
71               if (cu->dbg->sectiondata[IDX_debug_types] == NULL)
72                 return 1;
73
74               off = 0;
75               v4type = true;
76             }
77         }
78       else
79         if (off >= cu->dbg->sectiondata[IDX_debug_types]->d_size)
80           return 1;
81     }
82
83   *next_cu = __libdw_findcu (dwarf, off, v4type);
84   if (*next_cu == NULL)
85     return -1;
86
87   Dwarf_CU *next = (*next_cu);
88
89   if (version != NULL)
90     *version = next->version;
91
92   if (unit_type != NULL)
93     *unit_type = next->unit_type;
94
95   if (cudie != NULL)
96     {
97       if (next->version >= 2 && next->version <= 5
98           && next->unit_type >= DW_UT_compile
99           && next->unit_type <= DW_UT_split_type)
100         *cudie = CUDIE (next);
101       else
102         memset (cudie, '\0', sizeof (Dwarf_Die));
103     }
104
105   if (subdie != NULL)
106     {
107       if (next->version >= 2 && next->version <= 5)
108         {
109           /* For types, return the actual type DIE.  For skeletons,
110              find the associated split compile unit and return its
111              DIE.  */
112           if (next->unit_type == DW_UT_type
113               || next->unit_type == DW_UT_split_type)
114             *subdie = SUBDIE(next);
115           else if (next->unit_type == DW_UT_skeleton)
116             {
117               Dwarf_CU *split_cu = __libdw_find_split_unit (next);
118               if (split_cu != NULL)
119                 *subdie = CUDIE(split_cu);
120               else
121                 memset (subdie, '\0', sizeof (Dwarf_Die));
122             }
123           else
124             memset (subdie, '\0', sizeof (Dwarf_Die));
125         }
126       else
127         memset (subdie, '\0', sizeof (Dwarf_Die));
128     }
129
130   return 0;
131 }