xref: /illumos-gate/usr/src/lib/libdwarf/common/dwarf_dsc.c (revision a92282e44f968185a6bba094d1e5fece2da819cf)
1 /*
2   Copyright (C) 2016-2019 David Anderson. All Rights Reserved.
3 
4   This program is free software; you can redistribute it and/or modify it
5   under the terms of version 2.1 of the GNU Lesser General Public License
6   as published by the Free Software Foundation.
7 
8   This program is distributed in the hope that it would be useful, but
9   WITHOUT ANY WARRANTY; without even the implied warranty of
10   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 
12   Further, this software is distributed without any warranty that it is
13   free of the rightful claim of any third person regarding infringement
14   or the like.  Any license provided herein, whether implied or
15   otherwise, applies only to this software file.  Patent licenses, if
16   any, provided herein do not apply to combinations of this program with
17   other software, or any other product whatsoever.
18 
19   You should have received a copy of the GNU Lesser General Public
20   License along with this program; if not, write the Free Software
21   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
22   USA.
23 
24 */
25 
26 #include "config.h"
27 #include <stdio.h>
28 #ifdef HAVE_STDLIB_H
29 #include <stdlib.h>
30 #endif
31 #ifdef HAVE_MALLOC_H
32 /* Useful include for some Windows compilers. */
33 #include <malloc.h>
34 #endif /* HAVE_MALLOC_H */
35 #include "dwarf_incl.h"
36 #include "dwarf_alloc.h"
37 #include "dwarf_error.h"
38 #include "dwarf_util.h"
39 #include "dwarf_dsc.h"
40 
41 #define FALSE 0
42 #define TRUE 1
43 
44 /*  When called with ary and *arraycount 0
45     this just counts the elements found.
46     Otherwise it records the values in ary and
47     recounts. The arraycount pointer must be
48     passed-in non-null always. */
49 static int
50 get_dsc_leb_entries(Dwarf_Debug dbg,
51     Dwarf_Small    * blockpointer,
52     Dwarf_Unsigned   blocklen,
53     int dounsigned,
54     struct Dwarf_Dsc_Entry_s *ary,
55     size_t         * arraycount,
56     Dwarf_Error    * error)
57 {
58     Dwarf_Small *p = blockpointer;
59     Dwarf_Small *endp = blockpointer + blocklen;
60     size_t larraycount = 0;
61     size_t iarraycount = *arraycount;
62 
63     if (!ary) {
64         if (iarraycount) {
65             /* Internal botch calling this static function. */
66             _dwarf_error(dbg, error, DW_DLE_DISCR_ARRAY_ERROR);
67             return DW_DLV_ERROR;
68         }
69     } else {
70         if (!iarraycount) {
71             /* Internal botch calling this static function. */
72             _dwarf_error(dbg, error, DW_DLE_DISCR_ARRAY_ERROR);
73             return DW_DLV_ERROR;
74         }
75     }
76     if (dounsigned) {
77         while (p < endp)  {
78             Dwarf_Unsigned dsc = 0;
79             Dwarf_Unsigned low = 0;
80             Dwarf_Unsigned high = 0;
81             UNUSEDARG Dwarf_Unsigned leblen = 0;
82 
83             if (ary && (larraycount >= iarraycount)) {
84                 _dwarf_error(dbg, error, DW_DLE_DISCR_ARRAY_ERROR);
85                 return DW_DLV_ERROR;
86             }
87             DECODE_LEB128_UWORD_LEN_CK(p,dsc,
88                 leblen,dbg,error,endp);
89             if (!dsc) {
90                 DECODE_LEB128_UWORD_LEN_CK(p,low,
91                     leblen, dbg,error,endp);
92             } else {
93                 DECODE_LEB128_UWORD_LEN_CK(p,low,
94                     leblen, dbg,error,endp);
95                 DECODE_LEB128_UWORD_LEN_CK(p,high,
96                     leblen, dbg,error,endp);
97             }
98             if(ary) {
99                 struct Dwarf_Dsc_Entry_s *arye =
100                     ary+larraycount;
101 
102                 /*  type reads the same as uleb and leb because
103                     it is only zero or one. */
104                 arye->dsc_type = dsc;
105                 arye->dsc_low_u = low;
106                 arye->dsc_high_u = high;
107             }
108             larraycount++;
109         }
110     } else {
111         while (p < endp)  {
112             Dwarf_Signed dsc = 0;
113             Dwarf_Signed low = 0;
114             Dwarf_Signed high = 0;
115             UNUSEDARG Dwarf_Unsigned leblen = 0;
116 
117             if (ary && (larraycount >= iarraycount)) {
118                 _dwarf_error(dbg, error, DW_DLE_DISCR_ARRAY_ERROR);
119                 return DW_DLV_ERROR;
120             }
121             DECODE_LEB128_SWORD_LEN_CK(p,dsc,
122                 leblen,dbg,error,endp);
123             if (!dsc) {
124                 DECODE_LEB128_SWORD_LEN_CK(p,low,
125                     leblen,dbg,error,endp);
126             } else {
127                 DECODE_LEB128_SWORD_LEN_CK(p,low,
128                     leblen,dbg,error,endp);
129                 DECODE_LEB128_SWORD_LEN_CK(p,high,
130                     leblen,dbg,error,endp);
131             }
132             if(ary) {
133                 struct Dwarf_Dsc_Entry_s *arye =
134                     ary+larraycount;
135 
136                 /*  type reads the same as uleb and leb because
137                     it is only zero or one. */
138                 arye->dsc_type = (Dwarf_Unsigned)dsc;
139                 arye->dsc_low_s = low;
140                 arye->dsc_high_s = high;
141             }
142             larraycount++;
143         }
144     }
145     if (ary) {
146         /*  Just verify this recount matches original */
147         if(iarraycount != larraycount) {
148             _dwarf_error(dbg, error, DW_DLE_DISCR_ARRAY_ERROR);
149             return DW_DLV_ERROR;
150         }
151     } else {
152         /*  This matters for first call with
153             ary 0 and iarraycount 0 as we are generating the
154             count. */
155         *arraycount = larraycount;
156     }
157     return DW_DLV_OK;
158 }
159 
160 
161 int dwarf_discr_list(Dwarf_Debug dbg,
162     Dwarf_Small    * blockpointer,
163     Dwarf_Unsigned   blocklen,
164     Dwarf_Dsc_Head * dsc_head_out,
165     Dwarf_Unsigned * dsc_array_length_out,
166     Dwarf_Error    * error)
167 {
168     Dwarf_Dsc_Head h = 0;
169     int res = 0;
170     size_t arraycount = 0;
171     struct Dwarf_Dsc_Entry_s *ary = 0;
172     Dwarf_Small * dscblockp = 0;
173     Dwarf_Unsigned dscblocklen = 0;
174 
175     if (!dbg){
176         _dwarf_error(NULL, error, DW_DLE_DBG_NULL);          \
177         return DW_DLV_ERROR;
178     }
179     if (blocklen == 0) {
180         return DW_DLV_NO_ENTRY;
181     }
182     dscblockp = (Dwarf_Small *)calloc(blocklen,sizeof(Dwarf_Small));
183     if(!dscblockp) {
184         _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
185         return DW_DLV_ERROR;
186     }
187     dscblocklen = blocklen;
188     memcpy(dscblockp,blockpointer,blocklen);
189 
190     res = get_dsc_leb_entries(dbg,dscblockp,dscblocklen,
191         /*  TRUE or FALSE here is not important, the arraycount
192             returned to us will be identical either way. */
193         FALSE, 0, &arraycount,error);
194     if (res != DW_DLV_OK) {
195         free(dscblockp);
196         return res;
197     }
198 
199     h = (Dwarf_Dsc_Head)_dwarf_get_alloc(dbg,DW_DLA_DSC_HEAD,1);
200     if(!h) {
201         free(dscblockp);
202         _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
203         return DW_DLV_ERROR;
204     }
205 
206     h->dsh_block = dscblockp;
207     h->dsh_block_len = dscblocklen;
208     h->dsh_debug = dbg;
209     /* Now the destructor for h will deal with block malloc space. */
210 
211     ary = (struct Dwarf_Dsc_Entry_s *)calloc(arraycount,
212         sizeof(struct Dwarf_Dsc_Entry_s));
213     if(!ary) {
214         dwarf_dealloc(dbg,h,DW_DLA_DSC_HEAD);
215         _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
216         return DW_DLV_ERROR;
217     }
218     h->dsh_count = arraycount;
219     h->dsh_array = ary;
220     h->dsh_set_unsigned = 0;
221     h->dsh_set_signed = 0;
222 
223     *dsc_head_out = h;
224     *dsc_array_length_out = arraycount;
225     return DW_DLV_OK;
226 }
227 
228 /*  NEW September 2016. Allows easy access to DW_AT_discr_list
229     entry. Callers must know which is the appropriate
230     one of the following two interfaces, though both
231     will work. */
232 int dwarf_discr_entry_u(Dwarf_Dsc_Head  dsh ,
233     Dwarf_Unsigned   entrynum,
234     Dwarf_Half     * out_type,
235     Dwarf_Unsigned * out_discr_low,
236     Dwarf_Unsigned * out_discr_high,
237     UNUSEDARG Dwarf_Error    * error)
238 {
239     struct Dwarf_Dsc_Entry_s *dse = 0;
240 
241     if (entrynum >= dsh->dsh_count) {
242         return DW_DLV_NO_ENTRY;
243     }
244     if (!dsh->dsh_set_unsigned) {
245         int res =0;
246         int dounsigned = 1;
247         size_t count = dsh->dsh_count;
248 
249         res = get_dsc_leb_entries(dsh->dsh_debug,
250             dsh->dsh_block,
251             dsh->dsh_block_len,
252             dounsigned,
253             dsh->dsh_array,
254             &count,
255             error);
256         if (res != DW_DLV_OK) {
257             return res;
258         }
259         dsh->dsh_set_unsigned = TRUE;
260     }
261     if (!dsh->dsh_array) {
262         _dwarf_error(dsh->dsh_debug, error, DW_DLE_DISCR_ARRAY_ERROR);
263         return DW_DLV_ERROR;
264     }
265     dse = dsh->dsh_array + entrynum;
266     *out_type       = dse->dsc_type;
267     *out_discr_low  = dse->dsc_low_u;
268     *out_discr_high = dse->dsc_high_u;
269     return DW_DLV_OK;
270 }
271 
272 /*  NEW September 2016. Allows easy access to DW_AT_discr_list
273     entry. */
274 int dwarf_discr_entry_s(Dwarf_Dsc_Head  dsh,
275     Dwarf_Unsigned   entrynum,
276     Dwarf_Half     * out_type,
277     Dwarf_Signed   * out_discr_low,
278     Dwarf_Signed   * out_discr_high,
279     UNUSEDARG Dwarf_Error    * error)
280 {
281     struct Dwarf_Dsc_Entry_s *dse = 0;
282 
283     if (entrynum >= dsh->dsh_count) {
284         return DW_DLV_NO_ENTRY;
285     }
286     if (!dsh->dsh_set_signed) {
287         int res =0;
288         int dounsigned = 0;
289         size_t count = dsh->dsh_count;
290 
291         res = get_dsc_leb_entries(dsh->dsh_debug,
292             dsh->dsh_block,
293             dsh->dsh_block_len,
294             dounsigned,
295             dsh->dsh_array,
296             &count,
297             error);
298         if (res != DW_DLV_OK) {
299             return res;
300         }
301         dsh->dsh_set_signed = TRUE;
302     }
303     if (!dsh->dsh_array) {
304         _dwarf_error(dsh->dsh_debug, error, DW_DLE_DISCR_ARRAY_ERROR);
305         return DW_DLV_ERROR;
306     }
307     dse = dsh->dsh_array + entrynum;
308     *out_type       = dse->dsc_type;
309     *out_discr_low  = dse->dsc_low_s;
310     *out_discr_high = dse->dsc_high_s;
311     return DW_DLV_OK;
312 }
313 
314 void
315 _dwarf_dsc_destructor(void *m)
316 {
317     Dwarf_Dsc_Head h = (Dwarf_Dsc_Head) m;
318 
319     free(h->dsh_array);
320     h->dsh_array = 0;
321     free(h->dsh_block);
322     h->dsh_block = 0;
323     h->dsh_count = 0;
324 }
325