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 : 9476 : get_offset_from (Dwarf_Die *die, int name, Dwarf_Word *retp)
43 : : {
44 : : /* Get the appropriate attribute. */
45 : 9476 : Dwarf_Attribute attr;
46 [ + + ]: 9476 : if (INTUSE(dwarf_attr) (die, name, &attr) == NULL)
47 : : return -1;
48 : :
49 : : /* Offset into the corresponding section. */
50 [ - + ]: 6674 : if (INTUSE(dwarf_formudata) (&attr, retp) != 0)
51 : : return -1;
52 : :
53 : 6674 : Dwarf_Off offset;
54 [ - + ]: 6674 : if (INTUSE(dwarf_cu_dwp_section_info) (die->cu, DW_SECT_MACRO, &offset, NULL)
55 : : != 0)
56 : : return -1;
57 : 6674 : *retp += offset;
58 : 6674 : return 0;
59 : : }
60 : :
61 : : static int
62 : 11614 : macro_op_compare (const void *p1, const void *p2)
63 : : {
64 : 11614 : const Dwarf_Macro_Op_Table *t1 = (const Dwarf_Macro_Op_Table *) p1;
65 : 11614 : const Dwarf_Macro_Op_Table *t2 = (const Dwarf_Macro_Op_Table *) p2;
66 : :
67 [ + + ]: 11614 : if (t1->offset < t2->offset)
68 : : return -1;
69 [ + + ]: 11534 : 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 : 44 : build_table (Dwarf_Macro_Op_Table *table,
82 : : Dwarf_Macro_Op_Proto op_protos[static 255])
83 : : {
84 : 44 : unsigned ct = 0;
85 [ + + ]: 11264 : for (unsigned i = 1; i < 256; ++i)
86 [ + + ]: 11220 : if (op_protos[i - 1].forms != NULL)
87 : 434 : table->table[table->opcodes[i - 1] = ct++] = op_protos[i - 1];
88 : : else
89 : 10786 : table->opcodes[i - 1] = 0xff;
90 : 44 : }
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 : 14 : init_macinfo_table (void)
104 : : {
105 : 14 : MACRO_PROTO (p_udata_str, DW_FORM_udata, DW_FORM_string);
106 : 14 : MACRO_PROTO (p_udata_udata, DW_FORM_udata, DW_FORM_udata);
107 : 14 : MACRO_PROTO (p_none);
108 : :
109 : 14 : 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 : 14 : Dwarf_Macro_Op_Table *macinfo_table = (void *) macinfo_data;
121 : 14 : memset (macinfo_table, 0, sizeof macinfo_data);
122 : 14 : build_table (macinfo_table, op_protos);
123 : 14 : macinfo_table->sec_index = IDX_debug_macinfo;
124 : 14 : }
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 : 30 : 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 : 30 : const unsigned char *startp = readp;
173 : :
174 : : /* Request at least 3 bytes for header. */
175 [ - + ]: 30 : if (readp + 3 > endp)
176 : : {
177 : 0 : invalid_dwarf:
178 : 0 : __libdw_seterrno (DWARF_E_INVALID_DWARF);
179 : 0 : return NULL;
180 : : }
181 : :
182 [ - + ]: 30 : uint16_t version = read_2ubyte_unaligned_inc (dbg, readp);
183 [ - + ]: 30 : if (version != 4 && version != 5)
184 : : {
185 : 0 : __libdw_seterrno (DWARF_E_INVALID_VERSION);
186 : 0 : return NULL;
187 : : }
188 : :
189 : 30 : uint8_t flags = *readp++;
190 : 30 : bool is_64bit = (flags & 0x1) != 0;
191 : :
192 : 30 : Dwarf_Off line_offset = (Dwarf_Off) -1;
193 [ + + ]: 30 : 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 [ - + ]: 18 : else if (cudie != NULL)
200 : : {
201 : 0 : Dwarf_Attribute attr_mem, *attr
202 : 0 : = INTUSE(dwarf_attr) (cudie, DW_AT_stmt_list, &attr_mem);
203 [ # # ]: 0 : if (attr != NULL)
204 [ # # ]: 0 : if (unlikely (INTUSE(dwarf_formudata) (attr, &line_offset) != 0))
205 : 0 : return NULL;
206 : : }
207 [ + + + - ]: 30 : 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 : 30 : uint8_t address_size;
217 [ + + ]: 30 : if (cudie != NULL)
218 : 12 : 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 : 30 : MACRO_PROTO (p_udata_str, DW_FORM_udata, DW_FORM_string);
233 : 30 : MACRO_PROTO (p_udata_strp, DW_FORM_udata, DW_FORM_strp);
234 : 30 : MACRO_PROTO (p_udata_strsup, DW_FORM_udata, DW_FORM_strp_sup);
235 : 30 : MACRO_PROTO (p_udata_strx, DW_FORM_udata, DW_FORM_strx);
236 : 30 : MACRO_PROTO (p_udata_udata, DW_FORM_udata, DW_FORM_udata);
237 : 30 : MACRO_PROTO (p_secoffset, DW_FORM_sec_offset);
238 : 30 : MACRO_PROTO (p_none);
239 : :
240 : 30 : 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 [ + + ]: 30 : if ((flags & 0x4) != 0)
257 : : {
258 : 4 : unsigned count = *readp++;
259 [ + + ]: 8 : for (unsigned i = 0; i < count; ++i)
260 : : {
261 : 4 : unsigned opcode = *readp++;
262 : :
263 : 4 : Dwarf_Macro_Op_Proto e;
264 [ - + ]: 4 : if (readp >= endp)
265 : 0 : goto invalid;
266 : 4 : get_uleb128 (e.nforms, readp, endp);
267 : 4 : e.forms = readp;
268 : 4 : op_protos[opcode - 1] = e;
269 : :
270 : 4 : readp += e.nforms;
271 [ - + ]: 4 : if (readp > endp)
272 : : {
273 : 0 : invalid:
274 : 0 : __libdw_seterrno (DWARF_E_INVALID_DWARF);
275 : 0 : return NULL;
276 : : }
277 : : }
278 : : }
279 : :
280 : 30 : size_t ct = 0;
281 [ + + ]: 7680 : for (unsigned i = 1; i < 256; ++i)
282 [ + + ]: 7650 : if (op_protos[i - 1].forms != NULL)
283 : 364 : ++ct;
284 : :
285 : : /* We support at most 0xfe opcodes defined in the table, as 0xff is
286 : : a value that means that given opcode is not stored at all. But
287 : : that should be fine, as opcode 0 is not allocated. */
288 [ - + ]: 30 : assert (ct < 0xff);
289 : :
290 : 30 : size_t macop_table_size = offsetof (Dwarf_Macro_Op_Table, table[ct]);
291 : :
292 [ + + ]: 30 : Dwarf_Macro_Op_Table *table = libdw_alloc (dbg, Dwarf_Macro_Op_Table,
293 : : macop_table_size, 1);
294 : :
295 : 90 : *table = (Dwarf_Macro_Op_Table) {
296 : : .dbg = dbg,
297 : : .offset = macoff,
298 : : .sec_index = IDX_debug_macro,
299 : : .line_offset = line_offset,
300 [ + - ]: 30 : .header_len = readp - startp,
301 : : .version = version,
302 : : .address_size = address_size,
303 : : .offset_size = is_64bit ? 8 : 4,
304 : :
305 : : /* NULL if CUDIE is NULL or DW_AT_comp_dir is absent. */
306 : 30 : .comp_dir = __libdw_getcompdir (cudie),
307 : : };
308 : 30 : build_table (table, op_protos);
309 : :
310 : 30 : return table;
311 : : }
312 : :
313 : : static Dwarf_Macro_Op_Table *
314 : 7026 : cache_op_table (Dwarf *dbg, int sec_index, Dwarf_Off macoff,
315 : : const unsigned char *startp,
316 : : const unsigned char *const endp,
317 : : Dwarf_Die *cudie)
318 : : {
319 : 7026 : Dwarf_Macro_Op_Table fake = { .offset = macoff, .sec_index = sec_index };
320 : 7026 : Dwarf_Macro_Op_Table **found = eu_tfind (&fake, &dbg->macro_ops_tree,
321 : : macro_op_compare);
322 [ + + ]: 7026 : if (found != NULL)
323 : 6986 : return *found;
324 : :
325 : 80 : Dwarf_Macro_Op_Table *table = sec_index == IDX_debug_macro
326 : 30 : ? get_table_for_offset (dbg, macoff, startp, endp, cudie)
327 [ + + ]: 40 : : get_macinfo_table (dbg, macoff, cudie);
328 : :
329 [ - + ]: 40 : if (table == NULL)
330 : : return NULL;
331 : :
332 : 40 : Dwarf_Macro_Op_Table **ret = eu_tsearch (table, &dbg->macro_ops_tree,
333 : : macro_op_compare);
334 [ - + ]: 40 : if (unlikely (ret == NULL))
335 : : {
336 : 0 : __libdw_seterrno (DWARF_E_NOMEM);
337 : 0 : return NULL;
338 : : }
339 : :
340 : 40 : return *ret;
341 : : }
342 : :
343 : : static ptrdiff_t
344 : 7026 : read_macros (Dwarf *dbg, int sec_index,
345 : : Dwarf_Off macoff, int (*callback) (Dwarf_Macro *, void *),
346 : : void *arg, ptrdiff_t offset, bool accept_0xff,
347 : : Dwarf_Die *cudie)
348 : : {
349 : 7026 : Elf_Data *d = dbg->sectiondata[sec_index];
350 [ + - - + ]: 7026 : if (unlikely (d == NULL || d->d_buf == NULL))
351 : : {
352 : 0 : __libdw_seterrno (DWARF_E_NO_ENTRY);
353 : 0 : return -1;
354 : : }
355 : :
356 [ - + ]: 7026 : if (unlikely (macoff >= d->d_size))
357 : : {
358 : 0 : __libdw_seterrno (DWARF_E_INVALID_DWARF);
359 : 0 : return -1;
360 : : }
361 : :
362 : 7026 : const unsigned char *const startp = d->d_buf + macoff;
363 : 7026 : const unsigned char *const endp = d->d_buf + d->d_size;
364 : :
365 : 7026 : Dwarf_Macro_Op_Table *table = cache_op_table (dbg, sec_index, macoff,
366 : : startp, endp, cudie);
367 [ - + ]: 7026 : if (table == NULL)
368 : : return -1;
369 : :
370 [ + + ]: 7026 : if (offset == 0)
371 : 40 : offset = table->header_len;
372 : :
373 [ - + ]: 7026 : assert (offset >= 0);
374 [ - + ]: 7026 : assert (offset < endp - startp);
375 : 7026 : const unsigned char *readp = startp + offset;
376 : :
377 [ + - ]: 7026 : while (readp < endp)
378 : : {
379 : 7026 : unsigned int opcode = *readp++;
380 [ + + ]: 7026 : if (opcode == 0)
381 : : /* Nothing more to do. */
382 : 7026 : return 0;
383 : :
384 [ + + ]: 6988 : if (unlikely (opcode == 0xff && ! accept_0xff))
385 : : {
386 : : /* See comment below at dwarf_getmacros for explanation of
387 : : why we are doing this. */
388 : 2 : __libdw_seterrno (DWARF_E_INVALID_OPCODE);
389 : 2 : return -1;
390 : : }
391 : :
392 : 6986 : unsigned int idx = table->opcodes[opcode - 1];
393 [ - + ]: 6986 : if (idx == 0xff)
394 : : {
395 : 0 : __libdw_seterrno (DWARF_E_INVALID_OPCODE);
396 : 0 : return -1;
397 : : }
398 : :
399 : 6986 : Dwarf_Macro_Op_Proto *proto = &table->table[idx];
400 : :
401 : : /* A fake CU with bare minimum data to fool dwarf_formX into
402 : : doing the right thing with the attributes that we put out.
403 : : We pretend it is the same version as the actual table.
404 : : Version 4 for the old GNU extension, version 5 for DWARF5.
405 : : To handle DW_FORM_strx[1234] we set the .str_offsets_base
406 : : from the given CU.
407 : : XXX We will need to deal with DW_MACRO_import_sup and change
408 : : out the dbg somehow for the DW_FORM_sec_offset to make sense. */
409 : 13972 : Dwarf_CU fake_cu = {
410 : : .dbg = dbg,
411 : : .sec_idx = sec_index,
412 : 6986 : .version = table->version,
413 : 6986 : .offset_size = table->offset_size,
414 [ + + ]: 6986 : .str_off_base = str_offsets_base_off (dbg, (cudie != NULL
415 : : ? cudie->cu: NULL)),
416 : : .startp = (void *) startp + offset,
417 : : .endp = (void *) endp,
418 : : };
419 : :
420 : 6986 : Dwarf_Attribute *attributes;
421 : 6986 : Dwarf_Attribute *attributesp = NULL;
422 : 6986 : Dwarf_Attribute nattributes[8];
423 [ - + ]: 6986 : if (unlikely (proto->nforms > 8))
424 : : {
425 : 0 : attributesp = malloc (sizeof (Dwarf_Attribute) * proto->nforms);
426 [ # # ]: 0 : if (attributesp == NULL)
427 : : {
428 : 0 : __libdw_seterrno (DWARF_E_NOMEM);
429 : 0 : return -1;
430 : : }
431 : : attributes = attributesp;
432 : : }
433 : : else
434 : : attributes = &nattributes[0];
435 : :
436 [ + + ]: 20812 : for (Dwarf_Word i = 0; i < proto->nforms; ++i)
437 : : {
438 : : /* We pretend this is a DW_AT[_GNU]_macros attribute so that
439 : : DW_FORM_sec_offset forms get correctly interpreted as
440 : : offset into .debug_macro. XXX Deal with DW_MACRO_import_sup
441 : : (swap .dbg) for DW_FORM_sec_offset? */
442 : 27652 : attributes[i].code = (fake_cu.version == 4 ? DW_AT_GNU_macros
443 [ + + ]: 13826 : : DW_AT_macros);
444 : 13826 : attributes[i].form = proto->forms[i];
445 : 13826 : attributes[i].valp = (void *) readp;
446 : 13826 : attributes[i].cu = &fake_cu;
447 : :
448 : : /* We don't want forms that aren't allowed because they could
449 : : read from the "abbrev" like DW_FORM_implicit_const. */
450 [ - + ]: 13826 : if (! libdw_valid_user_form (attributes[i].form))
451 : : {
452 : 0 : __libdw_seterrno (DWARF_E_INVALID_DWARF);
453 : 0 : free (attributesp);
454 : 0 : return -1;
455 : : }
456 : :
457 : 13826 : size_t len = __libdw_form_val_len (&fake_cu, proto->forms[i], readp);
458 [ - + ]: 13826 : if (unlikely (len == (size_t) -1))
459 : : {
460 : 0 : free (attributesp);
461 : 0 : return -1;
462 : : }
463 : :
464 : 13826 : readp += len;
465 : : }
466 : :
467 : 6986 : Dwarf_Macro macro = {
468 : : .table = table,
469 : : .opcode = opcode,
470 : : .attributes = attributes,
471 : : };
472 : :
473 : 6986 : int res = callback (¯o, arg);
474 [ - + ]: 6986 : if (unlikely (attributesp != NULL))
475 : 0 : free (attributesp);
476 : :
477 [ + - ]: 6986 : if (res != DWARF_CB_OK)
478 : 6986 : return readp - startp;
479 : : }
480 : :
481 : : return 0;
482 : : }
483 : :
484 : : /* Token layout:
485 : :
486 : : - The highest bit is used for distinguishing between callers that
487 : : know that opcode 0xff may have one of two incompatible meanings.
488 : : The mask that we use for selecting this bit is
489 : : DWARF_GETMACROS_START.
490 : :
491 : : - The rest of the token (31 or 63 bits) encodes address inside the
492 : : macro unit.
493 : :
494 : : Besides, token value of 0 signals end of iteration and -1 is
495 : : reserved for signaling errors. That means it's impossible to
496 : : represent maximum offset of a .debug_macro unit to new-style
497 : : callers (which in practice decreases the permissible macro unit
498 : : size by another 1 byte). */
499 : :
500 : : static ptrdiff_t
501 : 7026 : token_from_offset (ptrdiff_t offset, bool accept_0xff)
502 : : {
503 [ + + ]: 7026 : if (offset == -1 || offset == 0)
504 : : return offset;
505 : :
506 : : /* Make sure the offset didn't overflow into the flag bit. */
507 [ - + ]: 6986 : if ((offset & DWARF_GETMACROS_START) != 0)
508 : : {
509 : 0 : __libdw_seterrno (DWARF_E_TOO_BIG);
510 : 0 : return -1;
511 : : }
512 : :
513 [ + + ]: 6986 : if (accept_0xff)
514 : 5934 : offset |= DWARF_GETMACROS_START;
515 : :
516 : : return offset;
517 : : }
518 : :
519 : : static ptrdiff_t
520 : 7026 : offset_from_token (ptrdiff_t token, bool *accept_0xffp)
521 : : {
522 : 7026 : *accept_0xffp = (token & DWARF_GETMACROS_START) != 0;
523 : 7026 : token &= ~DWARF_GETMACROS_START;
524 : :
525 : 7026 : return token;
526 : : }
527 : :
528 : : static ptrdiff_t
529 : 3692 : gnu_macros_getmacros_off (Dwarf *dbg, Dwarf_Off macoff,
530 : : int (*callback) (Dwarf_Macro *, void *),
531 : : void *arg, ptrdiff_t offset, bool accept_0xff,
532 : : Dwarf_Die *cudie)
533 : : {
534 [ - + ]: 3692 : assert (offset >= 0);
535 : :
536 [ - + ]: 3692 : if (macoff >= dbg->sectiondata[IDX_debug_macro]->d_size)
537 : : {
538 : 0 : __libdw_seterrno (DWARF_E_INVALID_OFFSET);
539 : 0 : return -1;
540 : : }
541 : :
542 : 3692 : return read_macros (dbg, IDX_debug_macro, macoff,
543 : : callback, arg, offset, accept_0xff, cudie);
544 : : }
545 : :
546 : : static ptrdiff_t
547 : 3334 : macro_info_getmacros_off (Dwarf *dbg, Dwarf_Off macoff,
548 : : int (*callback) (Dwarf_Macro *, void *),
549 : : void *arg, ptrdiff_t offset, Dwarf_Die *cudie)
550 : : {
551 [ - + ]: 3334 : assert (offset >= 0);
552 : :
553 : 3334 : return read_macros (dbg, IDX_debug_macinfo, macoff,
554 : : callback, arg, offset, true, cudie);
555 : : }
556 : :
557 : : ptrdiff_t
558 : 352 : dwarf_getmacros_off (Dwarf *dbg, Dwarf_Off macoff,
559 : : int (*callback) (Dwarf_Macro *, void *),
560 : : void *arg, ptrdiff_t token)
561 : : {
562 [ - + ]: 352 : if (dbg == NULL)
563 : : {
564 : 0 : __libdw_seterrno (DWARF_E_NO_DWARF);
565 : 0 : return -1;
566 : : }
567 : :
568 : 352 : bool accept_0xff;
569 : 352 : ptrdiff_t offset = offset_from_token (token, &accept_0xff);
570 [ - + ]: 352 : assert (accept_0xff);
571 : :
572 : 352 : offset = gnu_macros_getmacros_off (dbg, macoff, callback, arg, offset,
573 : : accept_0xff, NULL);
574 : :
575 : 352 : return token_from_offset (offset, accept_0xff);
576 : : }
577 : :
578 : : ptrdiff_t
579 : 6674 : dwarf_getmacros (Dwarf_Die *cudie, int (*callback) (Dwarf_Macro *, void *),
580 : : void *arg, ptrdiff_t token)
581 : : {
582 [ - + ]: 6674 : if (cudie == NULL)
583 : : {
584 : 0 : __libdw_seterrno (DWARF_E_NO_DWARF);
585 : 0 : return -1;
586 : : }
587 : :
588 : : /* This function might be called from a code that expects to see
589 : : DW_MACINFO_* opcodes, not DW_MACRO_{GNU_,}* ones. It is fine to
590 : : serve most DW_MACRO_{GNU_,}* opcodes to such code, because those
591 : : whose values are the same as DW_MACINFO_* ones also have the same
592 : : behavior. It is not very likely that a .debug_macro section
593 : : would only use the part of opcode space that it shares with
594 : : .debug_macinfo, but it is possible. Serving the opcodes that are
595 : : only valid in DW_MACRO_{GNU_,}* domain is OK as well, because
596 : : clients in general need to be ready that newer standards define
597 : : more opcodes, and have coping mechanisms for unfamiliar opcodes.
598 : :
599 : : The one exception to the above rule is opcode 0xff, which has
600 : : concrete semantics in .debug_macinfo, but falls into vendor block
601 : : in .debug_macro, and can be assigned to do whatever. There is
602 : : some small probability that the two opcodes would look
603 : : superficially similar enough that a client would be confused and
604 : : misbehave as a result. For this reason, we refuse to serve
605 : : through this interface 0xff's originating from .debug_macro
606 : : unless the TOKEN that we obtained indicates the call originates
607 : : from a new-style caller. See above for details on what
608 : : information is encoded into tokens. */
609 : :
610 : 6674 : bool accept_0xff;
611 : 6674 : ptrdiff_t offset = offset_from_token (token, &accept_0xff);
612 : :
613 : : /* DW_AT_macro_info */
614 [ + + ]: 6674 : if (dwarf_hasattr (cudie, DW_AT_macro_info))
615 : : {
616 : 3334 : Dwarf_Word macoff;
617 [ - + ]: 3334 : if (get_offset_from (cudie, DW_AT_macro_info, &macoff) != 0)
618 : 0 : return -1;
619 : 3334 : offset = macro_info_getmacros_off (cudie->cu->dbg, macoff,
620 : : callback, arg, offset, cudie);
621 : : }
622 : : else
623 : : {
624 : : /* DW_AT_GNU_macros, DW_AT_macros */
625 : 3340 : Dwarf_Word macoff;
626 [ + + ]: 3340 : if (get_offset_from (cudie, DW_AT_GNU_macros, &macoff) != 0
627 [ - + ]: 2802 : && get_offset_from (cudie, DW_AT_macros, &macoff) != 0)
628 : 0 : return -1;
629 : 3340 : offset = gnu_macros_getmacros_off (cudie->cu->dbg, macoff,
630 : : callback, arg, offset, accept_0xff,
631 : : cudie);
632 : : }
633 : :
634 : 6674 : return token_from_offset (offset, accept_0xff);
635 : : }
|