| GCC Code Coverage Report | |||||||||||||||||||||
        
  | 
    |||||||||||||||||||||
| Line | Branch | Exec | Source | 
1  | 
    /* $OpenBSD: dw.c,v 1.4 2017/09/27 08:59:38 mpi Exp $ */  | 
    ||
2  | 
    |||
3  | 
    /*  | 
    ||
4  | 
    * Copyright (c) 2016 Martin Pieuchot  | 
    ||
5  | 
    * Copyright (c) 2014 Matthew Dempsky <matthew@dempsky.org>  | 
    ||
6  | 
    *  | 
    ||
7  | 
    * Permission to use, copy, modify, and distribute this software for any  | 
    ||
8  | 
    * purpose with or without fee is hereby granted, provided that the above  | 
    ||
9  | 
    * copyright notice and this permission notice appear in all copies.  | 
    ||
10  | 
    *  | 
    ||
11  | 
    * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES  | 
    ||
12  | 
    * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF  | 
    ||
13  | 
    * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR  | 
    ||
14  | 
    * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES  | 
    ||
15  | 
    * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN  | 
    ||
16  | 
    * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF  | 
    ||
17  | 
    * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.  | 
    ||
18  | 
    */  | 
    ||
19  | 
    |||
20  | 
    #include <sys/queue.h>  | 
    ||
21  | 
    |||
22  | 
    #include <errno.h>  | 
    ||
23  | 
    #include <stdint.h>  | 
    ||
24  | 
    #include <stdlib.h>  | 
    ||
25  | 
    #include <string.h>  | 
    ||
26  | 
    |||
27  | 
    #include "dw.h"  | 
    ||
28  | 
    #include "dwarf.h"  | 
    ||
29  | 
    #include "pool.h"  | 
    ||
30  | 
    |||
31  | 
    #ifndef NOPOOL  | 
    ||
32  | 
    struct pool dcu_pool, die_pool, dav_pool, dab_pool, dat_pool;  | 
    ||
33  | 
    #endif /* NOPOOL */  | 
    ||
34  | 
    |||
35  | 
    #ifndef nitems  | 
    ||
36  | 
    #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))  | 
    ||
37  | 
    #endif  | 
    ||
38  | 
    |||
39  | 
    static int dw_read_u8(struct dwbuf *, uint8_t *);  | 
    ||
40  | 
    static int dw_read_u16(struct dwbuf *, uint16_t *);  | 
    ||
41  | 
    static int dw_read_u32(struct dwbuf *, uint32_t *);  | 
    ||
42  | 
    static int dw_read_u64(struct dwbuf *, uint64_t *);  | 
    ||
43  | 
    |||
44  | 
    static int dw_read_sleb128(struct dwbuf *, int64_t *);  | 
    ||
45  | 
    static int dw_read_uleb128(struct dwbuf *, uint64_t *);  | 
    ||
46  | 
    |||
47  | 
    static int dw_read_bytes(struct dwbuf *, void *, size_t);  | 
    ||
48  | 
    static int dw_read_string(struct dwbuf *, const char **);  | 
    ||
49  | 
    static int dw_read_buf(struct dwbuf *, struct dwbuf *, size_t);  | 
    ||
50  | 
    |||
51  | 
    static int dw_skip_bytes(struct dwbuf *, size_t);  | 
    ||
52  | 
    |||
53  | 
    static int dw_read_filename(struct dwbuf *, const char **, const char **,  | 
    ||
54  | 
    uint8_t, uint64_t);  | 
    ||
55  | 
    |||
56  | 
    |||
57  | 
    static int dw_attr_parse(struct dwbuf *, struct dwattr *, uint8_t,  | 
    ||
58  | 
    struct dwaval_queue *);  | 
    ||
59  | 
    static void dw_attr_purge(struct dwaval_queue *);  | 
    ||
60  | 
    static int dw_die_parse(struct dwbuf *, size_t, uint8_t,  | 
    ||
61  | 
    struct dwabbrev_queue *, struct dwdie_queue *);  | 
    ||
62  | 
    static void dw_die_purge(struct dwdie_queue *);  | 
    ||
63  | 
    |||
64  | 
    static int  | 
    ||
65  | 
    dw_read_bytes(struct dwbuf *d, void *v, size_t n)  | 
    ||
66  | 
    { | 
    ||
67  | 
    ✗✓ | 812  | 
    if (d->len < n)  | 
    
68  | 
    return -1;  | 
    ||
69  | 
    406  | 
    memcpy(v, d->buf, n);  | 
    |
70  | 
    406  | 
    d->buf += n;  | 
    |
71  | 
    406  | 
    d->len -= n;  | 
    |
72  | 
    406  | 
    return 0;  | 
    |
73  | 
    406  | 
    }  | 
    |
74  | 
    |||
75  | 
    static int  | 
    ||
76  | 
    dw_read_u8(struct dwbuf *d, uint8_t *v)  | 
    ||
77  | 
    { | 
    ||
78  | 
    648  | 
    return dw_read_bytes(d, v, sizeof(*v));  | 
    |
79  | 
    }  | 
    ||
80  | 
    |||
81  | 
    static int  | 
    ||
82  | 
    dw_read_u16(struct dwbuf *d, uint16_t *v)  | 
    ||
83  | 
    { | 
    ||
84  | 
    8  | 
    return dw_read_bytes(d, v, sizeof(*v));  | 
    |
85  | 
    }  | 
    ||
86  | 
    |||
87  | 
    static int  | 
    ||
88  | 
    dw_read_u32(struct dwbuf *d, uint32_t *v)  | 
    ||
89  | 
    { | 
    ||
90  | 
    136  | 
    return dw_read_bytes(d, v, sizeof(*v));  | 
    |
91  | 
    }  | 
    ||
92  | 
    |||
93  | 
    static int  | 
    ||
94  | 
    dw_read_u64(struct dwbuf *d, uint64_t *v)  | 
    ||
95  | 
    { | 
    ||
96  | 
    16  | 
    return dw_read_bytes(d, v, sizeof(*v));  | 
    |
97  | 
    }  | 
    ||
98  | 
    |||
99  | 
    /* Read a DWARF LEB128 (little-endian base-128) value. */  | 
    ||
100  | 
    static inline int  | 
    ||
101  | 
    dw_read_leb128(struct dwbuf *d, uint64_t *v, int signextend)  | 
    ||
102  | 
    { | 
    ||
103  | 
    unsigned int shift = 0;  | 
    ||
104  | 
    uint64_t res = 0;  | 
    ||
105  | 
    432  | 
    uint8_t x;  | 
    |
106  | 
    |||
107  | 
    ✓✗✓✗ | 
    648  | 
    	while (shift < 64 && !dw_read_u8(d, &x)) { | 
    
108  | 
    216  | 
    res |= (uint64_t)(x & 0x7f) << shift;  | 
    |
109  | 
    216  | 
    shift += 7;  | 
    |
110  | 
    ✗✓ | 216  | 
    		if ((x & 0x80) == 0) { | 
    
111  | 
    ✗✓✗✗ | 
    216  | 
    if (signextend && shift < 64 && (x & 0x40) != 0)  | 
    
112  | 
    res |= ~(uint64_t)0 << shift;  | 
    ||
113  | 
    216  | 
    *v = res;  | 
    |
114  | 
    216  | 
    return 0;  | 
    |
115  | 
    }  | 
    ||
116  | 
    }  | 
    ||
117  | 
    return -1;  | 
    ||
118  | 
    216  | 
    }  | 
    |
119  | 
    |||
120  | 
    static int  | 
    ||
121  | 
    dw_read_sleb128(struct dwbuf *d, int64_t *v)  | 
    ||
122  | 
    { | 
    ||
123  | 
    return dw_read_leb128(d, (uint64_t *)v, 1);  | 
    ||
124  | 
    }  | 
    ||
125  | 
    |||
126  | 
    static int  | 
    ||
127  | 
    dw_read_uleb128(struct dwbuf *d, uint64_t *v)  | 
    ||
128  | 
    { | 
    ||
129  | 
    432  | 
    return dw_read_leb128(d, v, 0);  | 
    |
130  | 
    }  | 
    ||
131  | 
    |||
132  | 
    /* Read a NUL terminated string. */  | 
    ||
133  | 
    static int  | 
    ||
134  | 
    dw_read_string(struct dwbuf *d, const char **s)  | 
    ||
135  | 
    { | 
    ||
136  | 
    const char *end = memchr(d->buf, '\0', d->len);  | 
    ||
137  | 
    size_t n;  | 
    ||
138  | 
    |||
139  | 
    if (end == NULL)  | 
    ||
140  | 
    return -1;  | 
    ||
141  | 
    |||
142  | 
    n = end - d->buf + 1;  | 
    ||
143  | 
    *s = d->buf;  | 
    ||
144  | 
    d->buf += n;  | 
    ||
145  | 
    d->len -= n;  | 
    ||
146  | 
    return 0;  | 
    ||
147  | 
    }  | 
    ||
148  | 
    |||
149  | 
    static int  | 
    ||
150  | 
    dw_read_buf(struct dwbuf *d, struct dwbuf *v, size_t n)  | 
    ||
151  | 
    { | 
    ||
152  | 
    ✗✓ | 32  | 
    if (d->len < n)  | 
    
153  | 
    return -1;  | 
    ||
154  | 
    16  | 
    v->buf = d->buf;  | 
    |
155  | 
    16  | 
    v->len = n;  | 
    |
156  | 
    16  | 
    d->buf += n;  | 
    |
157  | 
    16  | 
    d->len -= n;  | 
    |
158  | 
    16  | 
    return 0;  | 
    |
159  | 
    16  | 
    }  | 
    |
160  | 
    |||
161  | 
    static int  | 
    ||
162  | 
    dw_skip_bytes(struct dwbuf *d, size_t n)  | 
    ||
163  | 
    { | 
    ||
164  | 
    ✗✓ | 4  | 
    if (d->len < n)  | 
    
165  | 
    return -1;  | 
    ||
166  | 
    2  | 
    d->buf += n;  | 
    |
167  | 
    2  | 
    d->len -= n;  | 
    |
168  | 
    2  | 
    return 0;  | 
    |
169  | 
    2  | 
    }  | 
    |
170  | 
    |||
171  | 
    static int  | 
    ||
172  | 
    dw_read_filename(struct dwbuf *names, const char **outdirname,  | 
    ||
173  | 
    const char **outbasename, uint8_t opcode_base, uint64_t file)  | 
    ||
174  | 
    { | 
    ||
175  | 
    struct dwbuf dirnames;  | 
    ||
176  | 
    const char *basename = NULL, *dirname = NULL;  | 
    ||
177  | 
    uint64_t mtime, size, dummy, dir = 0;  | 
    ||
178  | 
    const char *name;  | 
    ||
179  | 
    size_t i;  | 
    ||
180  | 
    |||
181  | 
    if (file == 0)  | 
    ||
182  | 
    return -1;  | 
    ||
183  | 
    |||
184  | 
    /* Skip over opcode table. */  | 
    ||
185  | 
    	for (i = 1; i < opcode_base; i++) { | 
    ||
186  | 
    if (dw_read_uleb128(names, &dummy))  | 
    ||
187  | 
    return -1;  | 
    ||
188  | 
    }  | 
    ||
189  | 
    |||
190  | 
    /* Skip over directory name table for now. */  | 
    ||
191  | 
    dirnames = *names;  | 
    ||
192  | 
    	for (;;) { | 
    ||
193  | 
    if (dw_read_string(names, &name))  | 
    ||
194  | 
    return -1;  | 
    ||
195  | 
    if (*name == '\0')  | 
    ||
196  | 
    break;  | 
    ||
197  | 
    }  | 
    ||
198  | 
    |||
199  | 
    /* Locate file entry. */  | 
    ||
200  | 
    	for (i = 0; i < file; i++) { | 
    ||
201  | 
    if (dw_read_string(names, &basename) || *basename == '\0' ||  | 
    ||
202  | 
    dw_read_uleb128(names, &dir) ||  | 
    ||
203  | 
    dw_read_uleb128(names, &mtime) ||  | 
    ||
204  | 
    dw_read_uleb128(names, &size))  | 
    ||
205  | 
    return -1;  | 
    ||
206  | 
    }  | 
    ||
207  | 
    |||
208  | 
    	for (i = 0; i < dir; i++) { | 
    ||
209  | 
    if (!dw_read_string(&dirnames, &dirname) || *dirname == '\0')  | 
    ||
210  | 
    return -1;  | 
    ||
211  | 
    }  | 
    ||
212  | 
    |||
213  | 
    *outdirname = dirname;  | 
    ||
214  | 
    *outbasename = basename;  | 
    ||
215  | 
    |||
216  | 
    return 0;  | 
    ||
217  | 
    }  | 
    ||
218  | 
    |||
219  | 
    |||
220  | 
    const char *  | 
    ||
221  | 
    dw_tag2name(uint64_t tag)  | 
    ||
222  | 
    { | 
    ||
223  | 
    	static const char *dw_tags[] = { DW_TAG_NAMES }; | 
    ||
224  | 
    |||
225  | 
    if (tag <= nitems(dw_tags))  | 
    ||
226  | 
    return dw_tags[tag - 1];  | 
    ||
227  | 
    |||
228  | 
    if (tag == DW_TAG_lo_user)  | 
    ||
229  | 
    return "DW_TAG_lo_user";  | 
    ||
230  | 
    if (tag == DW_TAG_hi_user)  | 
    ||
231  | 
    return "DW_TAG_hi_user";  | 
    ||
232  | 
    |||
233  | 
    return NULL;  | 
    ||
234  | 
    }  | 
    ||
235  | 
    |||
236  | 
    const char *  | 
    ||
237  | 
    dw_at2name(uint64_t at)  | 
    ||
238  | 
    { | 
    ||
239  | 
    	static const char *dw_attrs[] = { DW_AT_NAMES }; | 
    ||
240  | 
    |||
241  | 
    if (at <= nitems(dw_attrs))  | 
    ||
242  | 
    return dw_attrs[at - 1];  | 
    ||
243  | 
    |||
244  | 
    if (at == DW_AT_lo_user)  | 
    ||
245  | 
    return "DW_AT_lo_user";  | 
    ||
246  | 
    if (at == DW_AT_hi_user)  | 
    ||
247  | 
    return "DW_AT_hi_user";  | 
    ||
248  | 
    |||
249  | 
    return NULL;  | 
    ||
250  | 
    }  | 
    ||
251  | 
    |||
252  | 
    const char *  | 
    ||
253  | 
    dw_form2name(uint64_t form)  | 
    ||
254  | 
    { | 
    ||
255  | 
    	static const char *dw_forms[] = { DW_FORM_NAMES }; | 
    ||
256  | 
    |||
257  | 
    if (form <= nitems(dw_forms))  | 
    ||
258  | 
    return dw_forms[form - 1];  | 
    ||
259  | 
    |||
260  | 
    if (form == DW_FORM_GNU_ref_alt)  | 
    ||
261  | 
    return "DW_FORM_GNU_ref_alt";  | 
    ||
262  | 
    if (form == DW_FORM_GNU_strp_alt)  | 
    ||
263  | 
    return "DW_FORM_GNU_strp_alt";  | 
    ||
264  | 
    |||
265  | 
    return NULL;  | 
    ||
266  | 
    }  | 
    ||
267  | 
    |||
268  | 
    const char *  | 
    ||
269  | 
    dw_op2name(uint8_t op)  | 
    ||
270  | 
    { | 
    ||
271  | 
    	static const char *dw_ops[] = { DW_OP_NAMES }; | 
    ||
272  | 
    |||
273  | 
    if (op <= nitems(dw_ops))  | 
    ||
274  | 
    return dw_ops[op - 1];  | 
    ||
275  | 
    |||
276  | 
    if (op == DW_OP_lo_user)  | 
    ||
277  | 
    return "DW_OP_lo_user";  | 
    ||
278  | 
    if (op == DW_OP_hi_user)  | 
    ||
279  | 
    return "DW_OP_hi_user";  | 
    ||
280  | 
    |||
281  | 
    return NULL;  | 
    ||
282  | 
    }  | 
    ||
283  | 
    |||
284  | 
    static int  | 
    ||
285  | 
    dw_attr_parse(struct dwbuf *dwbuf, struct dwattr *dat, uint8_t psz,  | 
    ||
286  | 
    struct dwaval_queue *davq)  | 
    ||
287  | 
    { | 
    ||
288  | 
    struct dwaval *dav;  | 
    ||
289  | 
    340  | 
    uint64_t form = dat->dat_form;  | 
    |
290  | 
    int error = 0, i = 0;  | 
    ||
291  | 
    |||
292  | 
    ✗✓ | 340  | 
    	while (form == DW_FORM_indirect) { | 
    
293  | 
    /* XXX loop prevention not strict enough? */  | 
    ||
294  | 
    if (dw_read_uleb128(dwbuf, &form) || (++i > 3))  | 
    ||
295  | 
    return ELOOP;  | 
    ||
296  | 
    }  | 
    ||
297  | 
    |||
298  | 
    170  | 
    dav = pzalloc(&dav_pool, sizeof(*dav));  | 
    |
299  | 
    ✗✓ | 170  | 
    if (dav == NULL)  | 
    
300  | 
    return ENOMEM;  | 
    ||
301  | 
    |||
302  | 
    170  | 
    dav->dav_dat = dat;  | 
    |
303  | 
    |||
304  | 
    ✗✓✓✗ ✗✗✗✗ ✓✗✓✗ ✓✗✗✗ ✗✗✗✓ ✗✗  | 
    170  | 
    	switch (form) { | 
    
305  | 
    case DW_FORM_addr:  | 
    ||
306  | 
    case DW_FORM_ref_addr:  | 
    ||
307  | 
    ✗✓ | 8  | 
    if (psz == sizeof(uint32_t))  | 
    
308  | 
    error = dw_read_u32(dwbuf, &dav->dav_u32);  | 
    ||
309  | 
    else  | 
    ||
310  | 
    8  | 
    error = dw_read_u64(dwbuf, &dav->dav_u64);  | 
    |
311  | 
    break;  | 
    ||
312  | 
    case DW_FORM_block1:  | 
    ||
313  | 
    14  | 
    error = dw_read_u8(dwbuf, &dav->dav_u8);  | 
    |
314  | 
    ✓✗ | 14  | 
    if (error == 0)  | 
    
315  | 
    14  | 
    error = dw_read_buf(dwbuf, &dav->dav_buf, dav->dav_u8);  | 
    |
316  | 
    break;  | 
    ||
317  | 
    case DW_FORM_block2:  | 
    ||
318  | 
    error = dw_read_u16(dwbuf, &dav->dav_u16);  | 
    ||
319  | 
    if (error == 0)  | 
    ||
320  | 
    error = dw_read_buf(dwbuf, &dav->dav_buf, dav->dav_u16);  | 
    ||
321  | 
    break;  | 
    ||
322  | 
    case DW_FORM_block4:  | 
    ||
323  | 
    error = dw_read_u32(dwbuf, &dav->dav_u32);  | 
    ||
324  | 
    if (error == 0)  | 
    ||
325  | 
    error = dw_read_buf(dwbuf, &dav->dav_buf, dav->dav_u32);  | 
    ||
326  | 
    break;  | 
    ||
327  | 
    case DW_FORM_block:  | 
    ||
328  | 
    error = dw_read_uleb128(dwbuf, &dav->dav_u64);  | 
    ||
329  | 
    if (error == 0)  | 
    ||
330  | 
    error = dw_read_buf(dwbuf, &dav->dav_buf, dav->dav_u64);  | 
    ||
331  | 
    break;  | 
    ||
332  | 
    case DW_FORM_data1:  | 
    ||
333  | 
    case DW_FORM_flag:  | 
    ||
334  | 
    case DW_FORM_ref1:  | 
    ||
335  | 
    80  | 
    error = dw_read_u8(dwbuf, &dav->dav_u8);  | 
    |
336  | 
    80  | 
    break;  | 
    |
337  | 
    case DW_FORM_data2:  | 
    ||
338  | 
    case DW_FORM_ref2:  | 
    ||
339  | 
    2  | 
    error = dw_read_u16(dwbuf, &dav->dav_u16);  | 
    |
340  | 
    2  | 
    break;  | 
    |
341  | 
    case DW_FORM_data4:  | 
    ||
342  | 
    case DW_FORM_ref4:  | 
    ||
343  | 
    28  | 
    error = dw_read_u32(dwbuf, &dav->dav_u32);  | 
    |
344  | 
    28  | 
    break;  | 
    |
345  | 
    case DW_FORM_data8:  | 
    ||
346  | 
    case DW_FORM_ref8:  | 
    ||
347  | 
    error = dw_read_u64(dwbuf, &dav->dav_u64);  | 
    ||
348  | 
    break;  | 
    ||
349  | 
    case DW_FORM_ref_udata:  | 
    ||
350  | 
    case DW_FORM_udata:  | 
    ||
351  | 
    error = dw_read_uleb128(dwbuf, &dav->dav_u64);  | 
    ||
352  | 
    break;  | 
    ||
353  | 
    case DW_FORM_sdata:  | 
    ||
354  | 
    error = dw_read_sleb128(dwbuf, &dav->dav_s64);  | 
    ||
355  | 
    break;  | 
    ||
356  | 
    case DW_FORM_string:  | 
    ||
357  | 
    error = dw_read_string(dwbuf, &dav->dav_str);  | 
    ||
358  | 
    break;  | 
    ||
359  | 
    case DW_FORM_strp:  | 
    ||
360  | 
    38  | 
    error = dw_read_u32(dwbuf, &dav->dav_u32);  | 
    |
361  | 
    38  | 
    break;  | 
    |
362  | 
    case DW_FORM_flag_present:  | 
    ||
363  | 
    dav->dav_u8 = 1;  | 
    ||
364  | 
    break;  | 
    ||
365  | 
    default:  | 
    ||
366  | 
    error = ENOENT;  | 
    ||
367  | 
    break;  | 
    ||
368  | 
    }  | 
    ||
369  | 
    |||
370  | 
    ✗✓ | 170  | 
    	if (error) { | 
    
371  | 
    pfree(&dav_pool, dav);  | 
    ||
372  | 
    return error;  | 
    ||
373  | 
    }  | 
    ||
374  | 
    |||
375  | 
    170  | 
    SIMPLEQ_INSERT_TAIL(davq, dav, dav_next);  | 
    |
376  | 
    170  | 
    return 0;  | 
    |
377  | 
    170  | 
    }  | 
    |
378  | 
    |||
379  | 
    static void  | 
    ||
380  | 
    dw_attr_purge(struct dwaval_queue *davq)  | 
    ||
381  | 
    { | 
    ||
382  | 
    struct dwaval *dav;  | 
    ||
383  | 
    |||
384  | 
    ✓✓ | 454  | 
    	while ((dav = SIMPLEQ_FIRST(davq)) != NULL) { | 
    
385  | 
    ✓✓ | 208  | 
    SIMPLEQ_REMOVE_HEAD(davq, dav_next);  | 
    
386  | 
    170  | 
    pfree(&dav_pool, dav);  | 
    |
387  | 
    }  | 
    ||
388  | 
    |||
389  | 
    38  | 
    SIMPLEQ_INIT(davq);  | 
    |
390  | 
    38  | 
    }  | 
    |
391  | 
    |||
392  | 
    static int  | 
    ||
393  | 
    dw_die_parse(struct dwbuf *dwbuf, size_t nextoff, uint8_t psz,  | 
    ||
394  | 
    struct dwabbrev_queue *dabq, struct dwdie_queue *dieq)  | 
    ||
395  | 
    { | 
    ||
396  | 
    struct dwdie *die;  | 
    ||
397  | 
    struct dwabbrev *dab;  | 
    ||
398  | 
    struct dwattr *dat;  | 
    ||
399  | 
    4  | 
    uint64_t code;  | 
    |
400  | 
    size_t doff;  | 
    ||
401  | 
    uint8_t lvl = 0;  | 
    ||
402  | 
    int error;  | 
    ||
403  | 
    |||
404  | 
    |||
405  | 
    ✓✓ | 84  | 
    	while (dwbuf->len > 0) { | 
    
406  | 
    42  | 
    doff = nextoff - dwbuf->len;  | 
    |
407  | 
    ✗✓ | 42  | 
    if (dw_read_uleb128(dwbuf, &code))  | 
    
408  | 
    return -1;  | 
    ||
409  | 
    |||
410  | 
    ✓✓ | 42  | 
    		if (code == 0) { | 
    
411  | 
    4  | 
    lvl--;  | 
    |
412  | 
    4  | 
    continue;  | 
    |
413  | 
    }  | 
    ||
414  | 
    |||
415  | 
    ✓✗ | 240  | 
    		SIMPLEQ_FOREACH(dab, dabq, dab_next) { | 
    
416  | 
    ✓✓ | 120  | 
    if (dab->dab_code == code)  | 
    
417  | 
    break;  | 
    ||
418  | 
    }  | 
    ||
419  | 
    ✗✓ | 38  | 
    if (dab == NULL)  | 
    
420  | 
    return ESRCH;  | 
    ||
421  | 
    |||
422  | 
    38  | 
    die = pmalloc(&die_pool, sizeof(*die));  | 
    |
423  | 
    ✗✓ | 38  | 
    if (die == NULL)  | 
    
424  | 
    return ENOMEM;  | 
    ||
425  | 
    |||
426  | 
    38  | 
    die->die_lvl = lvl;  | 
    |
427  | 
    38  | 
    die->die_dab = dab;  | 
    |
428  | 
    38  | 
    die->die_offset = doff;  | 
    |
429  | 
    38  | 
    SIMPLEQ_INIT(&die->die_avals);  | 
    |
430  | 
    |||
431  | 
    ✓✓ | 416  | 
    		SIMPLEQ_FOREACH(dat, &dab->dab_attrs, dat_next) { | 
    
432  | 
    170  | 
    error = dw_attr_parse(dwbuf, dat, psz, &die->die_avals);  | 
    |
433  | 
    ✗✓ | 170  | 
    			if (error != 0) { | 
    
434  | 
    dw_attr_purge(&die->die_avals);  | 
    ||
435  | 
    return error;  | 
    ||
436  | 
    }  | 
    ||
437  | 
    }  | 
    ||
438  | 
    |||
439  | 
    ✓✓ | 38  | 
    if (dab->dab_children == DW_CHILDREN_yes)  | 
    
440  | 
    4  | 
    lvl++;  | 
    |
441  | 
    |||
442  | 
    38  | 
    SIMPLEQ_INSERT_TAIL(dieq, die, die_next);  | 
    |
443  | 
    }  | 
    ||
444  | 
    |||
445  | 
    2  | 
    return 0;  | 
    |
446  | 
    2  | 
    }  | 
    |
447  | 
    |||
448  | 
    static void  | 
    ||
449  | 
    dw_die_purge(struct dwdie_queue *dieq)  | 
    ||
450  | 
    { | 
    ||
451  | 
    struct dwdie *die;  | 
    ||
452  | 
    |||
453  | 
    ✓✓ | 82  | 
    	while ((die = SIMPLEQ_FIRST(dieq)) != NULL) { | 
    
454  | 
    ✓✓ | 40  | 
    SIMPLEQ_REMOVE_HEAD(dieq, die_next);  | 
    
455  | 
    38  | 
    dw_attr_purge(&die->die_avals);  | 
    |
456  | 
    38  | 
    pfree(&die_pool, die);  | 
    |
457  | 
    }  | 
    ||
458  | 
    |||
459  | 
    2  | 
    SIMPLEQ_INIT(dieq);  | 
    |
460  | 
    2  | 
    }  | 
    |
461  | 
    |||
462  | 
    int  | 
    ||
463  | 
    dw_ab_parse(struct dwbuf *abseg, struct dwabbrev_queue *dabq)  | 
    ||
464  | 
    { | 
    ||
465  | 
    struct dwabbrev *dab;  | 
    ||
466  | 
    4  | 
    uint64_t code, tag;  | 
    |
467  | 
    2  | 
    uint8_t children;  | 
    |
468  | 
    |||
469  | 
    ✗✓ | 2  | 
    if (abseg->len == 0)  | 
    
470  | 
    return EINVAL;  | 
    ||
471  | 
    |||
472  | 
    	for (;;) { | 
    ||
473  | 
    ✓✓ | 14  | 
    if (dw_read_uleb128(abseg, &code) || (code == 0))  | 
    
474  | 
    break;  | 
    ||
475  | 
    |||
476  | 
    ✓✗✗✓ | 
    24  | 
    if (dw_read_uleb128(abseg, &tag) ||  | 
    
477  | 
    12  | 
    dw_read_u8(abseg, &children))  | 
    |
478  | 
    return -1;  | 
    ||
479  | 
    |||
480  | 
    12  | 
    dab = pmalloc(&dab_pool, sizeof(*dab));  | 
    |
481  | 
    ✗✓ | 12  | 
    if (dab == NULL)  | 
    
482  | 
    return ENOMEM;  | 
    ||
483  | 
    |||
484  | 
    12  | 
    dab->dab_code = code;  | 
    |
485  | 
    12  | 
    dab->dab_tag = tag;  | 
    |
486  | 
    12  | 
    dab->dab_children = children;  | 
    |
487  | 
    12  | 
    SIMPLEQ_INIT(&dab->dab_attrs);  | 
    |
488  | 
    |||
489  | 
    12  | 
    SIMPLEQ_INSERT_TAIL(dabq, dab, dab_next);  | 
    |
490  | 
    |||
491  | 
    12  | 
    		for (;;) { | 
    |
492  | 
    struct dwattr *dat;  | 
    ||
493  | 
    74  | 
    uint64_t attr = 0, form = 0;  | 
    |
494  | 
    |||
495  | 
    ✓✗✗✓ | 
    148  | 
    if (dw_read_uleb128(abseg, &attr) ||  | 
    
496  | 
    74  | 
    dw_read_uleb128(abseg, &form))  | 
    |
497  | 
    return -1;  | 
    ||
498  | 
    |||
499  | 
    ✓✓ | 74  | 
    if ((attr == 0) && (form == 0))  | 
    
500  | 
    12  | 
    break;  | 
    |
501  | 
    |||
502  | 
    62  | 
    dat = pmalloc(&dat_pool, sizeof(*dat));  | 
    |
503  | 
    ✗✓ | 62  | 
    if (dat == NULL)  | 
    
504  | 
    return ENOMEM;  | 
    ||
505  | 
    |||
506  | 
    62  | 
    dat->dat_attr = attr;  | 
    |
507  | 
    62  | 
    dat->dat_form = form;  | 
    |
508  | 
    |||
509  | 
    62  | 
    SIMPLEQ_INSERT_TAIL(&dab->dab_attrs, dat, dat_next);  | 
    |
510  | 
    ✓✓✓ | 148  | 
    }  | 
    
511  | 
    }  | 
    ||
512  | 
    |||
513  | 
    2  | 
    return 0;  | 
    |
514  | 
    2  | 
    }  | 
    |
515  | 
    |||
516  | 
    void  | 
    ||
517  | 
    dw_dabq_purge(struct dwabbrev_queue *dabq)  | 
    ||
518  | 
    { | 
    ||
519  | 
    struct dwabbrev *dab;  | 
    ||
520  | 
    |||
521  | 
    ✓✓ | 30  | 
    	while ((dab = SIMPLEQ_FIRST(dabq)) != NULL) { | 
    
522  | 
    struct dwattr *dat;  | 
    ||
523  | 
    |||
524  | 
    ✓✓ | 14  | 
    SIMPLEQ_REMOVE_HEAD(dabq, dab_next);  | 
    
525  | 
    ✓✓ | 136  | 
    		while ((dat = SIMPLEQ_FIRST(&dab->dab_attrs)) != NULL) { | 
    
526  | 
    ✓✓ | 74  | 
    SIMPLEQ_REMOVE_HEAD(&dab->dab_attrs, dat_next);  | 
    
527  | 
    62  | 
    pfree(&dat_pool, dat);  | 
    |
528  | 
    }  | 
    ||
529  | 
    |||
530  | 
    12  | 
    pfree(&dab_pool, dab);  | 
    |
531  | 
    }  | 
    ||
532  | 
    |||
533  | 
    2  | 
    SIMPLEQ_INIT(dabq);  | 
    |
534  | 
    2  | 
    }  | 
    |
535  | 
    |||
536  | 
    int  | 
    ||
537  | 
    dw_cu_parse(struct dwbuf *info, struct dwbuf *abbrev, size_t seglen,  | 
    ||
538  | 
    struct dwcu **dcup)  | 
    ||
539  | 
    { | 
    ||
540  | 
    8  | 
    struct dwbuf abseg = *abbrev;  | 
    |
541  | 
    4  | 
    struct dwbuf dwbuf;  | 
    |
542  | 
    size_t segoff, nextoff, addrsize;  | 
    ||
543  | 
    struct dwcu *dcu = NULL;  | 
    ||
544  | 
    4  | 
    uint32_t length = 0, abbroff = 0;  | 
    |
545  | 
    4  | 
    uint16_t version;  | 
    |
546  | 
    4  | 
    uint8_t psz;  | 
    |
547  | 
    int error;  | 
    ||
548  | 
    #ifndef NOPOOL  | 
    ||
549  | 
    static int dw_pool_inited = 0;  | 
    ||
550  | 
    |||
551  | 
    ✓✓ | 4  | 
    	if (!dw_pool_inited) { | 
    
552  | 
    2  | 
    pool_init(&dcu_pool, "dcu", 1, sizeof(struct dwcu));  | 
    |
553  | 
    2  | 
    pool_init(&dab_pool, "dab", 32, sizeof(struct dwabbrev));  | 
    |
554  | 
    2  | 
    pool_init(&dat_pool, "dat", 32, sizeof(struct dwattr));  | 
    |
555  | 
    2  | 
    pool_init(&die_pool, "die", 512, sizeof(struct dwdie));  | 
    |
556  | 
    2  | 
    pool_init(&dav_pool, "dav", 1024, sizeof(struct dwaval));  | 
    |
557  | 
    2  | 
    dw_pool_inited = 1;  | 
    |
558  | 
    2  | 
    }  | 
    |
559  | 
    #endif /* NOPOOL */  | 
    ||
560  | 
    |||
561  | 
    ✓✓✗✓ | 
    6  | 
    if (info->len == 0 || abbrev->len == 0)  | 
    
562  | 
    2  | 
    return EINVAL;  | 
    |
563  | 
    |||
564  | 
    /* Offset in the segment of the current Compile Unit. */  | 
    ||
565  | 
    2  | 
    segoff = seglen - info->len;  | 
    |
566  | 
    |||
567  | 
    ✗✓ | 2  | 
    if (dw_read_u32(info, &length))  | 
    
568  | 
    return -1;  | 
    ||
569  | 
    |||
570  | 
    ✓✗✗✓ | 
    4  | 
    if (length >= 0xfffffff0 || length > info->len)  | 
    
571  | 
    return EOVERFLOW;  | 
    ||
572  | 
    |||
573  | 
    /* Offset of the next Compile Unit. */  | 
    ||
574  | 
    2  | 
    nextoff = segoff + length + sizeof(uint32_t);  | 
    |
575  | 
    |||
576  | 
    ✗✓ | 2  | 
    if (dw_read_buf(info, &dwbuf, length))  | 
    
577  | 
    return -1;  | 
    ||
578  | 
    |||
579  | 
    addrsize = 4; /* XXX */  | 
    ||
580  | 
    |||
581  | 
    ✓✗✗✓ | 
    4  | 
    if (dw_read_u16(&dwbuf, &version) ||  | 
    
582  | 
    ✓✗ | 2  | 
    dw_read_bytes(&dwbuf, &abbroff, addrsize) ||  | 
    
583  | 
    2  | 
    dw_read_u8(&dwbuf, &psz))  | 
    |
584  | 
    return -1;  | 
    ||
585  | 
    |||
586  | 
    ✗✓ | 2  | 
    if (dw_skip_bytes(&abseg, abbroff))  | 
    
587  | 
    return -1;  | 
    ||
588  | 
    |||
589  | 
    /* Only DWARF2 until extended. */  | 
    ||
590  | 
    ✗✓ | 2  | 
    if (version != 2)  | 
    
591  | 
    return ENOTSUP;  | 
    ||
592  | 
    |||
593  | 
    2  | 
    dcu = pmalloc(&dcu_pool, sizeof(*dcu));  | 
    |
594  | 
    ✗✓ | 2  | 
    if (dcu == NULL)  | 
    
595  | 
    return ENOMEM;  | 
    ||
596  | 
    |||
597  | 
    2  | 
    dcu->dcu_offset = segoff;  | 
    |
598  | 
    2  | 
    dcu->dcu_length = length;  | 
    |
599  | 
    2  | 
    dcu->dcu_version = version;  | 
    |
600  | 
    2  | 
    dcu->dcu_abbroff = abbroff;  | 
    |
601  | 
    2  | 
    dcu->dcu_psize = psz;  | 
    |
602  | 
    2  | 
    SIMPLEQ_INIT(&dcu->dcu_abbrevs);  | 
    |
603  | 
    2  | 
    SIMPLEQ_INIT(&dcu->dcu_dies);  | 
    |
604  | 
    |||
605  | 
    2  | 
    error = dw_ab_parse(&abseg, &dcu->dcu_abbrevs);  | 
    |
606  | 
    ✗✓ | 2  | 
    	if (error != 0) { | 
    
607  | 
    dw_dcu_free(dcu);  | 
    ||
608  | 
    return error;  | 
    ||
609  | 
    }  | 
    ||
610  | 
    |||
611  | 
    2  | 
    error = dw_die_parse(&dwbuf, nextoff, psz, &dcu->dcu_abbrevs,  | 
    |
612  | 
    &dcu->dcu_dies);  | 
    ||
613  | 
    ✗✓ | 2  | 
    	if (error != 0) { | 
    
614  | 
    dw_dcu_free(dcu);  | 
    ||
615  | 
    return error;  | 
    ||
616  | 
    }  | 
    ||
617  | 
    |||
618  | 
    ✓✗ | 2  | 
    if (dcup != NULL)  | 
    
619  | 
    2  | 
    *dcup = dcu;  | 
    |
620  | 
    else  | 
    ||
621  | 
    dw_dcu_free(dcu);  | 
    ||
622  | 
    |||
623  | 
    2  | 
    return 0;  | 
    |
624  | 
    4  | 
    }  | 
    |
625  | 
    |||
626  | 
    void  | 
    ||
627  | 
    dw_dcu_free(struct dwcu *dcu)  | 
    ||
628  | 
    { | 
    ||
629  | 
    ✓✗ | 4  | 
    if (dcu == NULL)  | 
    
630  | 
    return;  | 
    ||
631  | 
    |||
632  | 
    2  | 
    dw_die_purge(&dcu->dcu_dies);  | 
    |
633  | 
    2  | 
    dw_dabq_purge(&dcu->dcu_abbrevs);  | 
    |
634  | 
    2  | 
    pfree(&dcu_pool, dcu);  | 
    |
635  | 
    4  | 
    }  | 
    |
636  | 
    |||
637  | 
    int  | 
    ||
638  | 
    dw_loc_parse(struct dwbuf *dwbuf, uint8_t *pop, uint64_t *poper1,  | 
    ||
639  | 
    uint64_t *poper2)  | 
    ||
640  | 
    { | 
    ||
641  | 
    uint64_t oper1 = 0, oper2 = 0;  | 
    ||
642  | 
    uint8_t op;  | 
    ||
643  | 
    |||
644  | 
    if (dw_read_u8(dwbuf, &op))  | 
    ||
645  | 
    return -1;  | 
    ||
646  | 
    |||
647  | 
    if (pop != NULL)  | 
    ||
648  | 
    *pop = op;  | 
    ||
649  | 
    |||
650  | 
    	switch (op) { | 
    ||
651  | 
    case DW_OP_constu:  | 
    ||
652  | 
    case DW_OP_plus_uconst:  | 
    ||
653  | 
    case DW_OP_regx:  | 
    ||
654  | 
    case DW_OP_piece:  | 
    ||
655  | 
    dw_read_uleb128(dwbuf, &oper1);  | 
    ||
656  | 
    break;  | 
    ||
657  | 
    |||
658  | 
    case DW_OP_consts:  | 
    ||
659  | 
    case DW_OP_breg0 ... DW_OP_breg31:  | 
    ||
660  | 
    case DW_OP_fbreg:  | 
    ||
661  | 
    dw_read_sleb128(dwbuf, &oper1);  | 
    ||
662  | 
    break;  | 
    ||
663  | 
    default:  | 
    ||
664  | 
    return ENOTSUP;  | 
    ||
665  | 
    }  | 
    ||
666  | 
    |||
667  | 
    if (poper1 != NULL)  | 
    ||
668  | 
    *poper1 = oper1;  | 
    ||
669  | 
    if (poper2 != NULL)  | 
    ||
670  | 
    *poper2 = oper2;  | 
    ||
671  | 
    |||
672  | 
    return 0;  | 
    ||
673  | 
    }  | 
    
| Generated by: GCOVR (Version 3.3) |