Branch data Line data Source code
1 : : /* Get macro information.
2 : : Copyright (C) 2002-2009, 2014, 2017, 2018 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 : : #ifdef HAVE_CONFIG_H
30 : : # include <config.h>
31 : : #endif
32 : :
33 : : #include <assert.h>
34 : : #include <dwarf.h>
35 : : #include <stdlib.h>
36 : : #include <string.h>
37 : :
38 : : #include <libdwP.h>
39 : : #include "eu-search.h"
40 : :
41 : : static int
42 : 9478 : get_offset_from (Dwarf_Die *die, int name, Dwarf_Word *retp)
43 : : {
44 : : /* Get the appropriate attribute. */
45 : 9478 : Dwarf_Attribute attr;
46 [ + + ]: 9478 : if (INTUSE(dwarf_attr) (die, name, &attr) == NULL)
47 : : return -1;
48 : :
49 : : /* Offset into the corresponding section. */
50 [ - + ]: 6676 : if (INTUSE(dwarf_formudata) (&attr, retp) != 0)
51 : : return -1;
52 : :
53 : 6676 : Dwarf_Off offset;
54 [ - + ]: 6676 : if (INTUSE(dwarf_cu_dwp_section_info) (die->cu, DW_SECT_MACRO, &offset, NULL)
55 : : != 0)
56 : : return -1;
57 : 6676 : *retp += offset;
58 : 6676 : return 0;
59 : : }
60 : :
61 : : static int
62 : 11680 : macro_op_compare (const void *p1, const void *p2)
63 : : {
64 : 11680 : const Dwarf_Macro_Op_Table *t1 = (const Dwarf_Macro_Op_Table *) p1;
65 : 11680 : const Dwarf_Macro_Op_Table *t2 = (const Dwarf_Macro_Op_Table *) p2;
66 : :
67 [ + + ]: 11680 : if (t1->offset < t2->offset)
68 : : return -1;
69 [ + + ]: 11600 : if (t1->offset > t2->offset)
70 : : return 1;
71 : :
72 [ + - ]: 6986 : if (t1->sec_index < t2->sec_index)
73 : : return -1;
74 [ - + ]: 6986 : if (t1->sec_index > t2->sec_index)
75 : 0 : return 1;
76 : :
77 : : return 0;
78 : : }
79 : :
80 : : static void
81 : 47 : build_table (Dwarf_Macro_Op_Table *table,
82 : : Dwarf_Macro_Op_Proto op_protos[static 255])
83 : : {
84 : 47 : unsigned ct = 0;
85 [ + + ]: 12032 : for (unsigned i = 1; i < 256; ++i)
86 [ + + ]: 11985 : if (op_protos[i - 1].forms != NULL)
87 : 449 : table->table[table->opcodes[i - 1] = ct++] = op_protos[i - 1];
88 : : else
89 : 11536 : table->opcodes[i - 1] = 0xff;
90 : 47 : }
91 : :
92 : : #define MACRO_PROTO(NAME, ...) \
93 : : Dwarf_Macro_Op_Proto NAME = ({ \
94 : : static const uint8_t proto[] = {__VA_ARGS__}; \
95 : : (Dwarf_Macro_Op_Proto) {sizeof proto, proto}; \
96 : : })
97 : :
98 : : enum { macinfo_data_size = offsetof (Dwarf_Macro_Op_Table, table[5]) };
99 : : static unsigned char macinfo_data[macinfo_data_size]
100 : : __attribute__ ((aligned (__alignof (Dwarf_Macro_Op_Table))));
101 : :
102 : : static __attribute__ ((constructor)) void
103 : 17 : init_macinfo_table (void)
104 : : {
105 : 17 : MACRO_PROTO (p_udata_str, DW_FORM_udata, DW_FORM_string);
106 : 17 : MACRO_PROTO (p_udata_udata, DW_FORM_udata, DW_FORM_udata);
107 : 17 : MACRO_PROTO (p_none);
108 : :
109 : 17 : Dwarf_Macro_Op_Proto op_protos[255] =
110 : : {
111 : : [DW_MACINFO_define - 1] = p_udata_str,
112 : : [DW_MACINFO_undef - 1] = p_udata_str,
113 : : [DW_MACINFO_vendor_ext - 1] = p_udata_str,
114 : : [DW_MACINFO_start_file - 1] = p_udata_udata,
115 : : [DW_MACINFO_end_file - 1] = p_none,
116 : : /* If you are adding more elements to this array, increase
117 : : MACINFO_DATA_SIZE above. */
118 : : };
119 : :
120 : 17 : Dwarf_Macro_Op_Table *macinfo_table = (void *) macinfo_data;
121 : 17 : memset (macinfo_table, 0, sizeof macinfo_data);
122 : 17 : build_table (macinfo_table, op_protos);
123 : 17 : macinfo_table->sec_index = IDX_debug_macinfo;
124 : 17 : }
125 : :
126 : : static Dwarf_Macro_Op_Table *
127 : 10 : get_macinfo_table (Dwarf *dbg, Dwarf_Word macoff, Dwarf_Die *cudie)
128 : : {
129 [ - + ]: 10 : assert (cudie != NULL);
130 : :
131 : 10 : Dwarf_Attribute attr_mem, *attr
132 : 10 : = INTUSE(dwarf_attr) (cudie, DW_AT_stmt_list, &attr_mem);
133 : 10 : Dwarf_Off line_offset = (Dwarf_Off) -1;
134 [ + + ]: 10 : if (attr != NULL)
135 : : {
136 [ - + ]: 4 : if (unlikely (INTUSE(dwarf_formudata) (attr, &line_offset) != 0))
137 : : return NULL;
138 : : }
139 [ + - ]: 6 : else if (cudie->cu->unit_type == DW_UT_split_compile
140 [ + - ]: 6 : && dbg->sectiondata[IDX_debug_line] != NULL)
141 : 6 : line_offset = 0;
142 [ + - ]: 10 : if (line_offset != (Dwarf_Off) -1)
143 : : {
144 : 10 : Dwarf_Off dwp_offset;
145 [ - + ]: 10 : if (INTUSE(dwarf_cu_dwp_section_info) (cudie->cu, DW_SECT_LINE,
146 : : &dwp_offset, NULL) != 0)
147 : 0 : return NULL;
148 : 10 : line_offset += dwp_offset;
149 : : }
150 : :
151 [ - + ]: 10 : Dwarf_Macro_Op_Table *table = libdw_alloc (dbg, Dwarf_Macro_Op_Table,
152 : : macinfo_data_size, 1);
153 : 10 : memcpy (table, macinfo_data, macinfo_data_size);
154 : :
155 : 10 : table->dbg = dbg;
156 : 10 : table->offset = macoff;
157 : 10 : table->sec_index = IDX_debug_macinfo;
158 : 10 : table->line_offset = line_offset;
159 : 10 : table->address_size = cudie->cu->address_size;
160 : 10 : table->offset_size = cudie->cu->offset_size;
161 : 10 : table->comp_dir = __libdw_getcompdir (cudie);
162 : :
163 : 10 : return table;
164 : : }
165 : :
166 : : static Dwarf_Macro_Op_Table *
167 : 32 : get_table_for_offset (Dwarf *dbg, Dwarf_Word macoff,
168 : : const unsigned char *readp,
169 : : const unsigned char *const endp,
170 : : Dwarf_Die *cudie)
171 : : {
172 : 32 : const unsigned char *startp = readp;
173 : :
174 : : /* Request at least 3 bytes for header. */
175 [ - + ]: 32 : if (readp + 3 > endp)
176 : : {
177 : 0 : invalid_dwarf:
178 : 0 : __libdw_seterrno (DWARF_E_INVALID_DWARF);
179 : 0 : return NULL;
180 : : }
181 : :
182 [ - + ]: 32 : uint16_t version = read_2ubyte_unaligned_inc (dbg, readp);
183 [ - + ]: 32 : if (version != 4 && version != 5)
184 : : {
185 : 0 : __libdw_seterrno (DWARF_E_INVALID_VERSION);
186 : 0 : return NULL;
187 : : }
188 : :
189 : 32 : uint8_t flags = *readp++;
190 : 32 : bool is_64bit = (flags & 0x1) != 0;
191 : :
192 : 32 : Dwarf_Off line_offset = (Dwarf_Off) -1;
193 [ + + ]: 32 : if ((flags & 0x2) != 0)
194 : : {
195 [ + - - + : 12 : line_offset = read_addr_unaligned_inc (is_64bit ? 8 : 4, dbg, readp);
- - ]
196 [ - + ]: 12 : if (readp > endp)
197 : 0 : goto invalid_dwarf;
198 : : }
199 [ + + ]: 20 : else if (cudie != NULL)
200 : : {
201 : 2 : Dwarf_Attribute attr_mem, *attr
202 : 2 : = INTUSE(dwarf_attr) (cudie, DW_AT_stmt_list, &attr_mem);
203 [ - + ]: 2 : if (attr != NULL)
204 [ # # ]: 0 : if (unlikely (INTUSE(dwarf_formudata) (attr, &line_offset) != 0))
205 : 0 : return NULL;
206 : : }
207 [ + + + - ]: 32 : if (line_offset != (Dwarf_Off) -1 && cudie != NULL)
208 : : {
209 : 12 : Dwarf_Off dwp_offset;
210 [ - + ]: 12 : if (INTUSE(dwarf_cu_dwp_section_info) (cudie->cu, DW_SECT_LINE,
211 : : &dwp_offset, NULL) != 0)
212 : 0 : return NULL;
213 : 12 : line_offset += dwp_offset;
214 : : }
215 : :
216 : 32 : uint8_t address_size;
217 [ + + ]: 32 : if (cudie != NULL)
218 : 14 : address_size = cudie->cu->address_size;
219 : : else
220 : : {
221 : 18 : char *ident = elf_getident (dbg->elf, NULL);
222 [ + - ]: 18 : address_size = ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
223 : : }
224 : :
225 : : /* """The macinfo entry types defined in this standard may, but
226 : : might not, be described in the table""".
227 : :
228 : : I.e. these may be present. It's tempting to simply skip them,
229 : : but it's probably more correct to tolerate that a producer tweaks
230 : : the way certain opcodes are encoded, for whatever reasons. */
231 : :
232 : 32 : MACRO_PROTO (p_udata_str, DW_FORM_udata, DW_FORM_string);
233 : 32 : MACRO_PROTO (p_udata_strp, DW_FORM_udata, DW_FORM_strp);
234 : 32 : MACRO_PROTO (p_udata_strsup, DW_FORM_udata, DW_FORM_strp_sup);
235 : 32 : MACRO_PROTO (p_udata_strx, DW_FORM_udata, DW_FORM_strx);
236 : 32 : MACRO_PROTO (p_udata_udata, DW_FORM_udata, DW_FORM_udata);
237 : 32 : MACRO_PROTO (p_secoffset, DW_FORM_sec_offset);
238 : 32 : MACRO_PROTO (p_none);
239 : :
240 : 32 : Dwarf_Macro_Op_Proto op_protos[255] =
241 : : {
242 : : [DW_MACRO_define - 1] = p_udata_str,
243 : : [DW_MACRO_undef - 1] = p_udata_str,
244 : : [DW_MACRO_define_strp - 1] = p_udata_strp,
245 : : [DW_MACRO_undef_strp - 1] = p_udata_strp,
246 : : [DW_MACRO_start_file - 1] = p_udata_udata,
247 : : [DW_MACRO_end_file - 1] = p_none,
248 : : [DW_MACRO_import - 1] = p_secoffset,
249 : : [DW_MACRO_define_sup - 1] = p_udata_strsup,
250 : : [DW_MACRO_undef_sup - 1] = p_udata_strsup,
251 : : [DW_MACRO_import_sup - 1] = p_secoffset, /* XXX - but in sup!. */
252 : : [DW_MACRO_define_strx - 1] = p_udata_strx,
253 : : [DW_MACRO_undef_strx - 1] = p_udata_strx,
254 : : };
255 : :
256 [ + + ]: 32 : if ((flags & 0x4) != 0)
257 : : {
258 [ - + ]: 6 : if (readp >= endp)
259 : 0 : goto invalid_dwarf;
260 : 6 : unsigned count = *readp++;
261 [ + + ]: 10 : for (unsigned i = 0; i < count; ++i)
262 : : {
263 [ - + ]: 6 : if (readp >= endp)
264 : 0 : goto invalid;
265 : 6 : unsigned opcode = *readp++;
266 : :
267 : : /* Opcode 0 is not allocated (and 0xff means "not stored").
268 : : Reject it here: without this check the unsigned expression
269 : : opcode - 1 wraps to UINT_MAX for opcode == 0, and the
270 : : assignment below would write a Dwarf_Macro_Op_Proto far out
271 : : of the bounds of the op_protos[255] stack array. */
272 [ + + ]: 6 : if (opcode == 0)
273 : 2 : goto invalid;
274 : :
275 : 4 : Dwarf_Macro_Op_Proto e;
276 [ - + ]: 4 : if (readp >= endp)
277 : 0 : goto invalid;
278 : 4 : get_uleb128 (e.nforms, readp, endp);
279 : 4 : e.forms = readp;
280 : 4 : op_protos[opcode - 1] = e;
281 : :
282 : 4 : readp += e.nforms;
283 [ - + ]: 4 : if (readp > endp)
284 : : {
285 : 0 : invalid:
286 : 2 : __libdw_seterrno (DWARF_E_INVALID_DWARF);
287 : 2 : return NULL;
288 : : }
289 : : }
290 : : }
291 : :
292 : 30 : size_t ct = 0;
293 [ + + ]: 7680 : for (unsigned i = 1; i < 256; ++i)
294 [ + + ]: 7650 : if (op_protos[i - 1].forms != NULL)
295 : 364 : ++ct;
296 : :
297 : : /* We support at most 0xfe opcodes defined in the table, as 0xff is
298 : : a value that means that given opcode is not stored at all. But
299 : : that should be fine, as opcode 0 is not allocated. */
300 [ - + ]: 30 : assert (ct < 0xff);
301 : :
302 : 30 : size_t macop_table_size = offsetof (Dwarf_Macro_Op_Table, table[ct]);
303 : :
304 [ + + ]: 30 : Dwarf_Macro_Op_Table *table = libdw_alloc (dbg, Dwarf_Macro_Op_Table,
305 : : macop_table_size, 1);
306 : :
307 : 90 : *table = (Dwarf_Macro_Op_Table) {
308 : : .dbg = dbg,
309 : : .offset = macoff,
310 : : .sec_index = IDX_debug_macro,
311 : : .line_offset = line_offset,
312 [ + - ]: 30 : .header_len = readp - startp,
313 : : .version = version,
314 : : .address_size = address_size,
315 : : .offset_size = is_64bit ? 8 : 4,
316 : :
317 : : /* NULL if CUDIE is NULL or DW_AT_comp_dir is absent. */
318 : 30 : .comp_dir = __libdw_getcompdir (cudie),
319 : : };
320 : 30 : build_table (table, op_protos);
321 : :
322 : 30 : return table;
323 : : }
324 : :
325 : : static Dwarf_Macro_Op_Table *
326 : 7028 : cache_op_table (Dwarf *dbg, int sec_index, Dwarf_Off macoff,
327 : : const unsigned char *startp,
328 : : const unsigned char *const endp,
329 : : Dwarf_Die *cudie)
330 : : {
331 : 7028 : Dwarf_Macro_Op_Table fake = { .offset = macoff, .sec_index = sec_index };
332 : 7028 : Dwarf_Macro_Op_Table **found = eu_tfind (&fake, &dbg->macro_ops_tree,
333 : : macro_op_compare);
334 [ + + ]: 7028 : if (found != NULL)
335 : 6986 : return *found;
336 : :
337 : 42 : mutex_lock (dbg->macro_lock);
338 : :
339 : 42 : found = eu_tfind_nolock (&fake, &dbg->macro_ops_tree, macro_op_compare);
340 [ - + ]: 42 : if (found != NULL)
341 : : {
342 : 0 : mutex_unlock (dbg->macro_lock);
343 : 0 : return *found;
344 : : }
345 : :
346 : 84 : Dwarf_Macro_Op_Table *table = sec_index == IDX_debug_macro
347 : 32 : ? get_table_for_offset (dbg, macoff, startp, endp, cudie)
348 [ + + ]: 42 : : get_macinfo_table (dbg, macoff, cudie);
349 : :
350 [ + + ]: 42 : if (table == NULL)
351 : : {
352 : : mutex_unlock (dbg->macro_lock);
353 : : return NULL;
354 : : }
355 : :
356 : 40 : Dwarf_Macro_Op_Table **ret = eu_tsearch_nolock (table, &dbg->macro_ops_tree,
357 : : macro_op_compare);
358 : 40 : mutex_unlock (dbg->macro_lock);
359 : :
360 [ - + ]: 40 : if (unlikely (ret == NULL))
361 : : {
362 : 0 : __libdw_seterrno (DWARF_E_NOMEM);
363 : 0 : return NULL;
364 : : }
365 : :
366 : 40 : return *ret;
367 : : }
368 : :
369 : : static ptrdiff_t
370 : 7028 : read_macros (Dwarf *dbg, int sec_index,
371 : : Dwarf_Off macoff, int (*callback) (Dwarf_Macro *, void *),
372 : : void *arg, ptrdiff_t offset, bool accept_0xff,
373 : : Dwarf_Die *cudie)
374 : : {
375 : 7028 : Elf_Data *d = dbg->sectiondata[sec_index];
376 [ + - - + ]: 7028 : if (unlikely (d == NULL || d->d_buf == NULL))
377 : : {
378 : 0 : __libdw_seterrno (DWARF_E_NO_ENTRY);
379 : 0 : return -1;
380 : : }
381 : :
382 [ - + ]: 7028 : if (unlikely (macoff >= d->d_size))
383 : : {
384 : 0 : __libdw_seterrno (DWARF_E_INVALID_DWARF);
385 : 0 : return -1;
386 : : }
387 : :
388 : 7028 : const unsigned char *const startp = d->d_buf + macoff;
389 : 7028 : const unsigned char *const endp = d->d_buf + d->d_size;
390 : :
391 : 7028 : Dwarf_Macro_Op_Table *table = cache_op_table (dbg, sec_index, macoff,
392 : : startp, endp, cudie);
393 [ + + ]: 7028 : if (table == NULL)
394 : : return -1;
395 : :
396 [ + + ]: 7026 : if (offset == 0)
397 : 40 : offset = table->header_len;
398 : :
399 [ - + ]: 7026 : assert (offset >= 0);
400 [ - + ]: 7026 : assert (offset < endp - startp);
401 : 7026 : const unsigned char *readp = startp + offset;
402 : :
403 [ + - ]: 7026 : while (readp < endp)
404 : : {
405 : 7026 : unsigned int opcode = *readp++;
406 [ + + ]: 7026 : if (opcode == 0)
407 : : /* Nothing more to do. */
408 : 7026 : return 0;
409 : :
410 [ + + ]: 6988 : if (unlikely (opcode == 0xff && ! accept_0xff))
411 : : {
412 : : /* See comment below at dwarf_getmacros for explanation of
413 : : why we are doing this. */
414 : 2 : __libdw_seterrno (DWARF_E_INVALID_OPCODE);
415 : 2 : return -1;
416 : : }
417 : :
418 : 6986 : unsigned int idx = table->opcodes[opcode - 1];
419 [ - + ]: 6986 : if (idx == 0xff)
420 : : {
421 : 0 : __libdw_seterrno (DWARF_E_INVALID_OPCODE);
422 : 0 : return -1;
423 : : }
424 : :
425 : 6986 : Dwarf_Macro_Op_Proto *proto = &table->table[idx];
426 : :
427 : : /* A fake CU with bare minimum data to fool dwarf_formX into
428 : : doing the right thing with the attributes that we put out.
429 : : We pretend it is the same version as the actual table.
430 : : Version 4 for the old GNU extension, version 5 for DWARF5.
431 : : To handle DW_FORM_strx[1234] we set the .str_offsets_base
432 : : from the given CU.
433 : : XXX We will need to deal with DW_MACRO_import_sup and change
434 : : out the dbg somehow for the DW_FORM_sec_offset to make sense. */
435 : 13972 : Dwarf_CU fake_cu = {
436 : : .dbg = dbg,
437 : : .sec_idx = sec_index,
438 : 6986 : .version = table->version,
439 : 6986 : .offset_size = table->offset_size,
440 [ + + ]: 6986 : .str_off_base = str_offsets_base_off (dbg, (cudie != NULL
441 : : ? cudie->cu: NULL)),
442 : : .startp = (void *) startp + offset,
443 : : .endp = (void *) endp,
444 : : };
445 : :
446 : 6986 : Dwarf_Attribute *attributes;
447 : 6986 : Dwarf_Attribute *attributesp = NULL;
448 : 6986 : Dwarf_Attribute nattributes[8];
449 [ - + ]: 6986 : if (unlikely (proto->nforms > 8))
450 : : {
451 : 0 : attributesp = malloc (sizeof (Dwarf_Attribute) * proto->nforms);
452 [ # # ]: 0 : if (attributesp == NULL)
453 : : {
454 : 0 : __libdw_seterrno (DWARF_E_NOMEM);
455 : 0 : return -1;
456 : : }
457 : : attributes = attributesp;
458 : : }
459 : : else
460 : : attributes = &nattributes[0];
461 : :
462 [ + + ]: 20812 : for (Dwarf_Word i = 0; i < proto->nforms; ++i)
463 : : {
464 : : /* We pretend this is a DW_AT[_GNU]_macros attribute so that
465 : : DW_FORM_sec_offset forms get correctly interpreted as
466 : : offset into .debug_macro. XXX Deal with DW_MACRO_import_sup
467 : : (swap .dbg) for DW_FORM_sec_offset? */
468 : 27652 : attributes[i].code = (fake_cu.version == 4 ? DW_AT_GNU_macros
469 [ + + ]: 13826 : : DW_AT_macros);
470 : 13826 : attributes[i].form = proto->forms[i];
471 : 13826 : attributes[i].valp = (void *) readp;
472 : 13826 : attributes[i].cu = &fake_cu;
473 : :
474 : : /* We don't want forms that aren't allowed because they could
475 : : read from the "abbrev" like DW_FORM_implicit_const. */
476 [ - + ]: 13826 : if (! libdw_valid_user_form (attributes[i].form))
477 : : {
478 : 0 : __libdw_seterrno (DWARF_E_INVALID_DWARF);
479 : 0 : free (attributesp);
480 : 0 : return -1;
481 : : }
482 : :
483 : 13826 : size_t len = __libdw_form_val_len (&fake_cu, proto->forms[i], readp);
484 [ - + ]: 13826 : if (unlikely (len == (size_t) -1))
485 : : {
486 : 0 : free (attributesp);
487 : 0 : return -1;
488 : : }
489 : :
490 : 13826 : readp += len;
491 : : }
492 : :
493 : 6986 : Dwarf_Macro macro = {
494 : : .table = table,
495 : : .opcode = opcode,
496 : : .attributes = attributes,
497 : : };
498 : :
499 : 6986 : int res = callback (¯o, arg);
500 [ - + ]: 6986 : if (unlikely (attributesp != NULL))
501 : 0 : free (attributesp);
502 : :
503 [ + - ]: 6986 : if (res != DWARF_CB_OK)
504 : 6986 : return readp - startp;
505 : : }
506 : :
507 : : return 0;
508 : : }
509 : :
510 : : /* Token layout:
511 : :
512 : : - The highest bit is used for distinguishing between callers that
513 : : know that opcode 0xff may have one of two incompatible meanings.
514 : : The mask that we use for selecting this bit is
515 : : DWARF_GETMACROS_START.
516 : :
517 : : - The rest of the token (31 or 63 bits) encodes address inside the
518 : : macro unit.
519 : :
520 : : Besides, token value of 0 signals end of iteration and -1 is
521 : : reserved for signaling errors. That means it's impossible to
522 : : represent maximum offset of a .debug_macro unit to new-style
523 : : callers (which in practice decreases the permissible macro unit
524 : : size by another 1 byte). */
525 : :
526 : : static ptrdiff_t
527 : 7028 : token_from_offset (ptrdiff_t offset, bool accept_0xff)
528 : : {
529 [ + + ]: 7028 : if (offset == -1 || offset == 0)
530 : : return offset;
531 : :
532 : : /* Make sure the offset didn't overflow into the flag bit. */
533 [ - + ]: 6986 : if ((offset & DWARF_GETMACROS_START) != 0)
534 : : {
535 : 0 : __libdw_seterrno (DWARF_E_TOO_BIG);
536 : 0 : return -1;
537 : : }
538 : :
539 [ + + ]: 6986 : if (accept_0xff)
540 : 5934 : offset |= DWARF_GETMACROS_START;
541 : :
542 : : return offset;
543 : : }
544 : :
545 : : static ptrdiff_t
546 : 7028 : offset_from_token (ptrdiff_t token, bool *accept_0xffp)
547 : : {
548 : 7028 : *accept_0xffp = (token & DWARF_GETMACROS_START) != 0;
549 : 7028 : token &= ~DWARF_GETMACROS_START;
550 : :
551 : 7028 : return token;
552 : : }
553 : :
554 : : static ptrdiff_t
555 : 3694 : gnu_macros_getmacros_off (Dwarf *dbg, Dwarf_Off macoff,
556 : : int (*callback) (Dwarf_Macro *, void *),
557 : : void *arg, ptrdiff_t offset, bool accept_0xff,
558 : : Dwarf_Die *cudie)
559 : : {
560 [ - + ]: 3694 : assert (offset >= 0);
561 : :
562 [ - + ]: 3694 : if (macoff >= dbg->sectiondata[IDX_debug_macro]->d_size)
563 : : {
564 : 0 : __libdw_seterrno (DWARF_E_INVALID_OFFSET);
565 : 0 : return -1;
566 : : }
567 : :
568 : 3694 : return read_macros (dbg, IDX_debug_macro, macoff,
569 : : callback, arg, offset, accept_0xff, cudie);
570 : : }
571 : :
572 : : static ptrdiff_t
573 : 3334 : macro_info_getmacros_off (Dwarf *dbg, Dwarf_Off macoff,
574 : : int (*callback) (Dwarf_Macro *, void *),
575 : : void *arg, ptrdiff_t offset, Dwarf_Die *cudie)
576 : : {
577 [ - + ]: 3334 : assert (offset >= 0);
578 : :
579 : 3334 : return read_macros (dbg, IDX_debug_macinfo, macoff,
580 : : callback, arg, offset, true, cudie);
581 : : }
582 : :
583 : : ptrdiff_t
584 : 352 : dwarf_getmacros_off (Dwarf *dbg, Dwarf_Off macoff,
585 : : int (*callback) (Dwarf_Macro *, void *),
586 : : void *arg, ptrdiff_t token)
587 : : {
588 [ - + ]: 352 : if (dbg == NULL)
589 : : {
590 : 0 : __libdw_seterrno (DWARF_E_NO_DWARF);
591 : 0 : return -1;
592 : : }
593 : :
594 : 352 : bool accept_0xff;
595 : 352 : ptrdiff_t offset = offset_from_token (token, &accept_0xff);
596 [ - + ]: 352 : assert (accept_0xff);
597 : :
598 : 352 : offset = gnu_macros_getmacros_off (dbg, macoff, callback, arg, offset,
599 : : accept_0xff, NULL);
600 : :
601 : 352 : return token_from_offset (offset, accept_0xff);
602 : : }
603 : :
604 : : ptrdiff_t
605 : 6676 : dwarf_getmacros (Dwarf_Die *cudie, int (*callback) (Dwarf_Macro *, void *),
606 : : void *arg, ptrdiff_t token)
607 : : {
608 [ - + ]: 6676 : if (cudie == NULL)
609 : : {
610 : 0 : __libdw_seterrno (DWARF_E_NO_DWARF);
611 : 0 : return -1;
612 : : }
613 : :
614 : : /* This function might be called from a code that expects to see
615 : : DW_MACINFO_* opcodes, not DW_MACRO_{GNU_,}* ones. It is fine to
616 : : serve most DW_MACRO_{GNU_,}* opcodes to such code, because those
617 : : whose values are the same as DW_MACINFO_* ones also have the same
618 : : behavior. It is not very likely that a .debug_macro section
619 : : would only use the part of opcode space that it shares with
620 : : .debug_macinfo, but it is possible. Serving the opcodes that are
621 : : only valid in DW_MACRO_{GNU_,}* domain is OK as well, because
622 : : clients in general need to be ready that newer standards define
623 : : more opcodes, and have coping mechanisms for unfamiliar opcodes.
624 : :
625 : : The one exception to the above rule is opcode 0xff, which has
626 : : concrete semantics in .debug_macinfo, but falls into vendor block
627 : : in .debug_macro, and can be assigned to do whatever. There is
628 : : some small probability that the two opcodes would look
629 : : superficially similar enough that a client would be confused and
630 : : misbehave as a result. For this reason, we refuse to serve
631 : : through this interface 0xff's originating from .debug_macro
632 : : unless the TOKEN that we obtained indicates the call originates
633 : : from a new-style caller. See above for details on what
634 : : information is encoded into tokens. */
635 : :
636 : 6676 : bool accept_0xff;
637 : 6676 : ptrdiff_t offset = offset_from_token (token, &accept_0xff);
638 : :
639 : : /* DW_AT_macro_info */
640 [ + + ]: 6676 : if (dwarf_hasattr (cudie, DW_AT_macro_info))
641 : : {
642 : 3334 : Dwarf_Word macoff;
643 [ - + ]: 3334 : if (get_offset_from (cudie, DW_AT_macro_info, &macoff) != 0)
644 : 0 : return -1;
645 : 3334 : offset = macro_info_getmacros_off (cudie->cu->dbg, macoff,
646 : : callback, arg, offset, cudie);
647 : : }
648 : : else
649 : : {
650 : : /* DW_AT_GNU_macros, DW_AT_macros */
651 : 3342 : Dwarf_Word macoff;
652 [ + + ]: 3342 : if (get_offset_from (cudie, DW_AT_GNU_macros, &macoff) != 0
653 [ - + ]: 2802 : && get_offset_from (cudie, DW_AT_macros, &macoff) != 0)
654 : 0 : return -1;
655 : 3342 : offset = gnu_macros_getmacros_off (cudie->cu->dbg, macoff,
656 : : callback, arg, offset, accept_0xff,
657 : : cudie);
658 : : }
659 : :
660 : 6676 : return token_from_offset (offset, accept_0xff);
661 : : }
|