Line data Source code
1 : /* Get macro information.
2 : Copyright (C) 2002-2009, 2014 Red Hat, Inc.
3 : This file is part of elfutils.
4 : Written by Ulrich Drepper <drepper@redhat.com>, 2002.
5 :
6 : This file is free software; you can redistribute it and/or modify
7 : it under the terms of either
8 :
9 : * the GNU Lesser General Public License as published by the Free
10 : Software Foundation; either version 3 of the License, or (at
11 : your option) any later version
12 :
13 : or
14 :
15 : * the GNU General Public License as published by the Free
16 : Software Foundation; either version 2 of the License, or (at
17 : your option) any later version
18 :
19 : or both in parallel, as here.
20 :
21 : elfutils is distributed in the hope that it will be useful, but
22 : WITHOUT ANY WARRANTY; without even the implied warranty of
23 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 : General Public License for more details.
25 :
26 : You should have received copies of the GNU General Public License and
27 : the GNU Lesser General Public License along with this program. If
28 : not, see <http://www.gnu.org/licenses/>. */
29 :
30 : #ifdef HAVE_CONFIG_H
31 : # include <config.h>
32 : #endif
33 :
34 : #include <assert.h>
35 : #include <dwarf.h>
36 : #include <search.h>
37 : #include <stdlib.h>
38 : #include <string.h>
39 :
40 : #include <libdwP.h>
41 :
42 : static int
43 535 : get_offset_from (Dwarf_Die *die, int name, Dwarf_Word *retp)
44 : {
45 : /* Get the appropriate attribute. */
46 : Dwarf_Attribute attr;
47 535 : if (INTUSE(dwarf_attr) (die, name, &attr) == NULL)
48 : return -1;
49 :
50 : /* Offset into the corresponding section. */
51 535 : return INTUSE(dwarf_formudata) (&attr, retp);
52 : }
53 :
54 : static int
55 1135 : macro_op_compare (const void *p1, const void *p2)
56 : {
57 1135 : const Dwarf_Macro_Op_Table *t1 = (const Dwarf_Macro_Op_Table *) p1;
58 1135 : const Dwarf_Macro_Op_Table *t2 = (const Dwarf_Macro_Op_Table *) p2;
59 :
60 1135 : if (t1->offset < t2->offset)
61 : return -1;
62 1095 : if (t1->offset > t2->offset)
63 : return 1;
64 :
65 697 : if (t1->sec_index < t2->sec_index)
66 : return -1;
67 697 : if (t1->sec_index > t2->sec_index)
68 : return 1;
69 :
70 697 : return 0;
71 : }
72 :
73 : static void
74 : build_table (Dwarf_Macro_Op_Table *table,
75 : Dwarf_Macro_Op_Proto op_protos[static 255])
76 : {
77 17 : unsigned ct = 0;
78 4352 : for (unsigned i = 1; i < 256; ++i)
79 4335 : if (op_protos[i - 1].forms != NULL)
80 111 : table->table[table->opcodes[i - 1] = ct++] = op_protos[i - 1];
81 : else
82 4224 : table->opcodes[i - 1] = 0xff;
83 : }
84 :
85 : #define MACRO_PROTO(NAME, ...) \
86 : Dwarf_Macro_Op_Proto NAME = ({ \
87 : static const uint8_t proto[] = {__VA_ARGS__}; \
88 : (Dwarf_Macro_Op_Proto) {sizeof proto, proto}; \
89 : })
90 :
91 : enum { macinfo_data_size = offsetof (Dwarf_Macro_Op_Table, table[5]) };
92 : static unsigned char macinfo_data[macinfo_data_size]
93 : __attribute__ ((aligned (__alignof (Dwarf_Macro_Op_Table))));
94 :
95 : static __attribute__ ((constructor)) void
96 5 : init_macinfo_table (void)
97 : {
98 5 : MACRO_PROTO (p_udata_str, DW_FORM_udata, DW_FORM_string);
99 5 : MACRO_PROTO (p_udata_udata, DW_FORM_udata, DW_FORM_udata);
100 5 : MACRO_PROTO (p_none);
101 :
102 5 : Dwarf_Macro_Op_Proto op_protos[255] =
103 : {
104 : [DW_MACINFO_define - 1] = p_udata_str,
105 : [DW_MACINFO_undef - 1] = p_udata_str,
106 : [DW_MACINFO_vendor_ext - 1] = p_udata_str,
107 : [DW_MACINFO_start_file - 1] = p_udata_udata,
108 : [DW_MACINFO_end_file - 1] = p_none,
109 : /* If you are adding more elements to this array, increase
110 : MACINFO_DATA_SIZE above. */
111 : };
112 :
113 5 : Dwarf_Macro_Op_Table *macinfo_table = (void *) macinfo_data;
114 5 : memset (macinfo_table, 0, sizeof macinfo_data);
115 5 : build_table (macinfo_table, op_protos);
116 5 : macinfo_table->sec_index = IDX_debug_macinfo;
117 5 : }
118 :
119 : static Dwarf_Macro_Op_Table *
120 2 : get_macinfo_table (Dwarf *dbg, Dwarf_Word macoff, Dwarf_Die *cudie)
121 : {
122 2 : assert (cudie != NULL);
123 :
124 2 : Dwarf_Attribute attr_mem, *attr
125 : = INTUSE(dwarf_attr) (cudie, DW_AT_stmt_list, &attr_mem);
126 2 : Dwarf_Off line_offset = (Dwarf_Off) -1;
127 2 : if (attr != NULL)
128 2 : if (unlikely (INTUSE(dwarf_formudata) (attr, &line_offset) != 0))
129 : return NULL;
130 :
131 2 : Dwarf_Macro_Op_Table *table = libdw_alloc (dbg, Dwarf_Macro_Op_Table,
132 : macinfo_data_size, 1);
133 2 : memcpy (table, macinfo_data, macinfo_data_size);
134 :
135 2 : table->offset = macoff;
136 2 : table->sec_index = IDX_debug_macinfo;
137 2 : table->line_offset = line_offset;
138 2 : table->is_64bit = cudie->cu->address_size == 8;
139 2 : table->comp_dir = __libdw_getcompdir (cudie);
140 :
141 2 : return table;
142 : }
143 :
144 : static Dwarf_Macro_Op_Table *
145 12 : get_table_for_offset (Dwarf *dbg, Dwarf_Word macoff,
146 : const unsigned char *readp,
147 : const unsigned char *const endp,
148 : Dwarf_Die *cudie)
149 : {
150 12 : const unsigned char *startp = readp;
151 :
152 : /* Request at least 3 bytes for header. */
153 12 : if (readp + 3 > endp)
154 : {
155 : invalid_dwarf:
156 0 : __libdw_seterrno (DWARF_E_INVALID_DWARF);
157 0 : return NULL;
158 : }
159 :
160 12 : uint16_t version = read_2ubyte_unaligned_inc (dbg, readp);
161 12 : if (version != 4)
162 : {
163 0 : __libdw_seterrno (DWARF_E_INVALID_VERSION);
164 0 : return NULL;
165 : }
166 :
167 12 : uint8_t flags = *readp++;
168 12 : bool is_64bit = (flags & 0x1) != 0;
169 :
170 12 : Dwarf_Off line_offset = (Dwarf_Off) -1;
171 12 : if ((flags & 0x2) != 0)
172 : {
173 3 : line_offset = read_addr_unaligned_inc (is_64bit ? 8 : 4, dbg, readp);
174 3 : if (readp > endp)
175 : goto invalid_dwarf;
176 : }
177 9 : else if (cudie != NULL)
178 : {
179 0 : Dwarf_Attribute attr_mem, *attr
180 : = INTUSE(dwarf_attr) (cudie, DW_AT_stmt_list, &attr_mem);
181 0 : if (attr != NULL)
182 0 : if (unlikely (INTUSE(dwarf_formudata) (attr, &line_offset) != 0))
183 0 : return NULL;
184 : }
185 :
186 : /* """The macinfo entry types defined in this standard may, but
187 : might not, be described in the table""".
188 :
189 : I.e. these may be present. It's tempting to simply skip them,
190 : but it's probably more correct to tolerate that a producer tweaks
191 : the way certain opcodes are encoded, for whatever reasons. */
192 :
193 12 : MACRO_PROTO (p_udata_str, DW_FORM_udata, DW_FORM_string);
194 12 : MACRO_PROTO (p_udata_strp, DW_FORM_udata, DW_FORM_strp);
195 12 : MACRO_PROTO (p_udata_udata, DW_FORM_udata, DW_FORM_udata);
196 12 : MACRO_PROTO (p_secoffset, DW_FORM_sec_offset);
197 12 : MACRO_PROTO (p_none);
198 :
199 12 : Dwarf_Macro_Op_Proto op_protos[255] =
200 : {
201 : [DW_MACRO_GNU_define - 1] = p_udata_str,
202 : [DW_MACRO_GNU_undef - 1] = p_udata_str,
203 : [DW_MACRO_GNU_define_indirect - 1] = p_udata_strp,
204 : [DW_MACRO_GNU_undef_indirect - 1] = p_udata_strp,
205 : [DW_MACRO_GNU_start_file - 1] = p_udata_udata,
206 : [DW_MACRO_GNU_end_file - 1] = p_none,
207 : [DW_MACRO_GNU_transparent_include - 1] = p_secoffset,
208 : /* N.B. DW_MACRO_undef_indirectx, DW_MACRO_define_indirectx
209 : should be added when 130313.1 is supported. */
210 : };
211 :
212 12 : if ((flags & 0x4) != 0)
213 : {
214 2 : unsigned count = *readp++;
215 4 : for (unsigned i = 0; i < count; ++i)
216 : {
217 2 : unsigned opcode = *readp++;
218 :
219 : Dwarf_Macro_Op_Proto e;
220 2 : if (readp >= endp)
221 : goto invalid;
222 2 : get_uleb128 (e.nforms, readp, endp);
223 2 : e.forms = readp;
224 2 : op_protos[opcode - 1] = e;
225 :
226 2 : readp += e.nforms;
227 2 : if (readp > endp)
228 : {
229 : invalid:
230 0 : __libdw_seterrno (DWARF_E_INVALID_DWARF);
231 0 : return NULL;
232 : }
233 : }
234 : }
235 :
236 12 : size_t ct = 0;
237 3072 : for (unsigned i = 1; i < 256; ++i)
238 3060 : if (op_protos[i - 1].forms != NULL)
239 86 : ++ct;
240 :
241 : /* We support at most 0xfe opcodes defined in the table, as 0xff is
242 : a value that means that given opcode is not stored at all. But
243 : that should be fine, as opcode 0 is not allocated. */
244 12 : assert (ct < 0xff);
245 :
246 12 : size_t macop_table_size = offsetof (Dwarf_Macro_Op_Table, table[ct]);
247 :
248 12 : Dwarf_Macro_Op_Table *table = libdw_alloc (dbg, Dwarf_Macro_Op_Table,
249 : macop_table_size, 1);
250 :
251 24 : *table = (Dwarf_Macro_Op_Table) {
252 : .offset = macoff,
253 : .sec_index = IDX_debug_macro,
254 : .line_offset = line_offset,
255 12 : .header_len = readp - startp,
256 : .version = version,
257 : .is_64bit = is_64bit,
258 :
259 : /* NULL if CUDIE is NULL or DW_AT_comp_dir is absent. */
260 12 : .comp_dir = __libdw_getcompdir (cudie),
261 : };
262 : build_table (table, op_protos);
263 :
264 : return table;
265 : }
266 :
267 : static Dwarf_Macro_Op_Table *
268 711 : cache_op_table (Dwarf *dbg, int sec_index, Dwarf_Off macoff,
269 : const unsigned char *startp,
270 : const unsigned char *const endp,
271 : Dwarf_Die *cudie)
272 : {
273 711 : Dwarf_Macro_Op_Table fake = { .offset = macoff, .sec_index = sec_index };
274 711 : Dwarf_Macro_Op_Table **found = tfind (&fake, &dbg->macro_ops,
275 : macro_op_compare);
276 711 : if (found != NULL)
277 697 : return *found;
278 :
279 14 : Dwarf_Macro_Op_Table *table = sec_index == IDX_debug_macro
280 : ? get_table_for_offset (dbg, macoff, startp, endp, cudie)
281 14 : : get_macinfo_table (dbg, macoff, cudie);
282 :
283 14 : if (table == NULL)
284 : return NULL;
285 :
286 14 : Dwarf_Macro_Op_Table **ret = tsearch (table, &dbg->macro_ops,
287 : macro_op_compare);
288 14 : if (unlikely (ret == NULL))
289 : {
290 0 : __libdw_seterrno (DWARF_E_NOMEM);
291 0 : return NULL;
292 : }
293 :
294 14 : return *ret;
295 : }
296 :
297 : static ptrdiff_t
298 711 : read_macros (Dwarf *dbg, int sec_index,
299 : Dwarf_Off macoff, int (*callback) (Dwarf_Macro *, void *),
300 : void *arg, ptrdiff_t offset, bool accept_0xff,
301 : Dwarf_Die *cudie)
302 : {
303 711 : Elf_Data *d = dbg->sectiondata[sec_index];
304 711 : if (unlikely (d == NULL || d->d_buf == NULL))
305 : {
306 0 : __libdw_seterrno (DWARF_E_NO_ENTRY);
307 0 : return -1;
308 : }
309 :
310 711 : if (unlikely (macoff >= d->d_size))
311 : {
312 0 : __libdw_seterrno (DWARF_E_INVALID_DWARF);
313 0 : return -1;
314 : }
315 :
316 711 : const unsigned char *const startp = d->d_buf + macoff;
317 711 : const unsigned char *const endp = d->d_buf + d->d_size;
318 :
319 711 : Dwarf_Macro_Op_Table *table = cache_op_table (dbg, sec_index, macoff,
320 : startp, endp, cudie);
321 711 : if (table == NULL)
322 : return -1;
323 :
324 711 : if (offset == 0)
325 14 : offset = table->header_len;
326 :
327 711 : assert (offset >= 0);
328 711 : assert (offset < endp - startp);
329 711 : const unsigned char *readp = startp + offset;
330 :
331 1422 : while (readp < endp)
332 : {
333 711 : unsigned int opcode = *readp++;
334 711 : if (opcode == 0)
335 : /* Nothing more to do. */
336 711 : return 0;
337 :
338 698 : if (unlikely (opcode == 0xff && ! accept_0xff))
339 : {
340 : /* See comment below at dwarf_getmacros for explanation of
341 : why we are doing this. */
342 1 : __libdw_seterrno (DWARF_E_INVALID_OPCODE);
343 1 : return -1;
344 : }
345 :
346 697 : unsigned int idx = table->opcodes[opcode - 1];
347 697 : if (idx == 0xff)
348 : {
349 0 : __libdw_seterrno (DWARF_E_INVALID_OPCODE);
350 0 : return -1;
351 : }
352 :
353 697 : Dwarf_Macro_Op_Proto *proto = &table->table[idx];
354 :
355 : /* A fake CU with bare minimum data to fool dwarf_formX into
356 : doing the right thing with the attributes that we put out.
357 : We arbitrarily pretend it's version 4. */
358 1394 : Dwarf_CU fake_cu = {
359 : .dbg = dbg,
360 : .version = 4,
361 697 : .offset_size = table->is_64bit ? 8 : 4,
362 : .startp = (void *) startp + offset,
363 : .endp = (void *) endp,
364 : };
365 :
366 : Dwarf_Attribute *attributes;
367 697 : Dwarf_Attribute *attributesp = NULL;
368 : Dwarf_Attribute nattributes[8];
369 697 : if (unlikely (proto->nforms > 8))
370 : {
371 0 : attributesp = malloc (sizeof (Dwarf_Attribute) * proto->nforms);
372 0 : if (attributesp == NULL)
373 : {
374 0 : __libdw_seterrno (DWARF_E_NOMEM);
375 0 : return -1;
376 : }
377 : attributes = attributesp;
378 : }
379 : else
380 : attributes = &nattributes[0];
381 :
382 2054 : for (Dwarf_Word i = 0; i < proto->nforms; ++i)
383 : {
384 : /* We pretend this is a DW_AT_GNU_macros attribute so that
385 : DW_FORM_sec_offset forms get correctly interpreted as
386 : offset into .debug_macro. */
387 1357 : attributes[i].code = DW_AT_GNU_macros;
388 1357 : attributes[i].form = proto->forms[i];
389 1357 : attributes[i].valp = (void *) readp;
390 1357 : attributes[i].cu = &fake_cu;
391 :
392 1357 : size_t len = __libdw_form_val_len (&fake_cu, proto->forms[i], readp);
393 1357 : if (unlikely (len == (size_t) -1))
394 : {
395 0 : free (attributesp);
396 0 : return -1;
397 : }
398 :
399 1357 : readp += len;
400 : }
401 :
402 697 : Dwarf_Macro macro = {
403 : .table = table,
404 : .opcode = opcode,
405 : .attributes = attributes,
406 : };
407 :
408 697 : int res = callback (¯o, arg);
409 697 : if (unlikely (attributesp != NULL))
410 0 : free (attributesp);
411 :
412 697 : if (res != DWARF_CB_OK)
413 697 : return readp - startp;
414 : }
415 :
416 : return 0;
417 : }
418 :
419 : /* Token layout:
420 :
421 : - The highest bit is used for distinguishing between callers that
422 : know that opcode 0xff may have one of two incompatible meanings.
423 : The mask that we use for selecting this bit is
424 : DWARF_GETMACROS_START.
425 :
426 : - The rest of the token (31 or 63 bits) encodes address inside the
427 : macro unit.
428 :
429 : Besides, token value of 0 signals end of iteration and -1 is
430 : reserved for signaling errors. That means it's impossible to
431 : represent maximum offset of a .debug_macro unit to new-style
432 : callers (which in practice decreases the permissible macro unit
433 : size by another 1 byte). */
434 :
435 : static ptrdiff_t
436 : token_from_offset (ptrdiff_t offset, bool accept_0xff)
437 : {
438 711 : if (offset == -1 || offset == 0)
439 : return offset;
440 :
441 : /* Make sure the offset didn't overflow into the flag bit. */
442 697 : if ((offset & DWARF_GETMACROS_START) != 0)
443 : {
444 0 : __libdw_seterrno (DWARF_E_TOO_BIG);
445 : return -1;
446 : }
447 :
448 530 : if (accept_0xff)
449 171 : offset |= DWARF_GETMACROS_START;
450 :
451 : return offset;
452 : }
453 :
454 : static ptrdiff_t
455 : offset_from_token (ptrdiff_t token, bool *accept_0xffp)
456 : {
457 711 : *accept_0xffp = (token & DWARF_GETMACROS_START) != 0;
458 711 : token &= ~DWARF_GETMACROS_START;
459 :
460 : return token;
461 : }
462 :
463 : static ptrdiff_t
464 445 : gnu_macros_getmacros_off (Dwarf *dbg, Dwarf_Off macoff,
465 : int (*callback) (Dwarf_Macro *, void *),
466 : void *arg, ptrdiff_t offset, bool accept_0xff,
467 : Dwarf_Die *cudie)
468 : {
469 445 : assert (offset >= 0);
470 :
471 445 : if (macoff >= dbg->sectiondata[IDX_debug_macro]->d_size)
472 : {
473 0 : __libdw_seterrno (DWARF_E_INVALID_OFFSET);
474 0 : return -1;
475 : }
476 :
477 445 : return read_macros (dbg, IDX_debug_macro, macoff,
478 : callback, arg, offset, accept_0xff, cudie);
479 : }
480 :
481 : static ptrdiff_t
482 266 : macro_info_getmacros_off (Dwarf *dbg, Dwarf_Off macoff,
483 : int (*callback) (Dwarf_Macro *, void *),
484 : void *arg, ptrdiff_t offset, Dwarf_Die *cudie)
485 : {
486 266 : assert (offset >= 0);
487 :
488 266 : return read_macros (dbg, IDX_debug_macinfo, macoff,
489 : callback, arg, offset, true, cudie);
490 : }
491 :
492 : ptrdiff_t
493 176 : dwarf_getmacros_off (Dwarf *dbg, Dwarf_Off macoff,
494 : int (*callback) (Dwarf_Macro *, void *),
495 : void *arg, ptrdiff_t token)
496 : {
497 176 : if (dbg == NULL)
498 : {
499 0 : __libdw_seterrno (DWARF_E_NO_DWARF);
500 0 : return -1;
501 : }
502 :
503 : bool accept_0xff;
504 176 : ptrdiff_t offset = offset_from_token (token, &accept_0xff);
505 176 : assert (accept_0xff);
506 :
507 176 : offset = gnu_macros_getmacros_off (dbg, macoff, callback, arg, offset,
508 : accept_0xff, NULL);
509 :
510 176 : return token_from_offset (offset, accept_0xff);
511 : }
512 :
513 : ptrdiff_t
514 535 : dwarf_getmacros (Dwarf_Die *cudie, int (*callback) (Dwarf_Macro *, void *),
515 : void *arg, ptrdiff_t token)
516 : {
517 535 : if (cudie == NULL)
518 : {
519 0 : __libdw_seterrno (DWARF_E_NO_DWARF);
520 0 : return -1;
521 : }
522 :
523 : /* This function might be called from a code that expects to see
524 : DW_MACINFO_* opcodes, not DW_MACRO_{GNU_,}* ones. It is fine to
525 : serve most DW_MACRO_{GNU_,}* opcodes to such code, because those
526 : whose values are the same as DW_MACINFO_* ones also have the same
527 : behavior. It is not very likely that a .debug_macro section
528 : would only use the part of opcode space that it shares with
529 : .debug_macinfo, but it is possible. Serving the opcodes that are
530 : only valid in DW_MACRO_{GNU_,}* domain is OK as well, because
531 : clients in general need to be ready that newer standards define
532 : more opcodes, and have coping mechanisms for unfamiliar opcodes.
533 :
534 : The one exception to the above rule is opcode 0xff, which has
535 : concrete semantics in .debug_macinfo, but falls into vendor block
536 : in .debug_macro, and can be assigned to do whatever. There is
537 : some small probability that the two opcodes would look
538 : superficially similar enough that a client would be confused and
539 : misbehave as a result. For this reason, we refuse to serve
540 : through this interface 0xff's originating from .debug_macro
541 : unless the TOKEN that we obtained indicates the call originates
542 : from a new-style caller. See above for details on what
543 : information is encoded into tokens. */
544 :
545 : bool accept_0xff;
546 535 : ptrdiff_t offset = offset_from_token (token, &accept_0xff);
547 :
548 : /* DW_AT_macro_info */
549 535 : if (dwarf_hasattr (cudie, DW_AT_macro_info))
550 : {
551 : Dwarf_Word macoff;
552 266 : if (get_offset_from (cudie, DW_AT_macro_info, &macoff) != 0)
553 0 : return -1;
554 266 : offset = macro_info_getmacros_off (cudie->cu->dbg, macoff,
555 : callback, arg, offset, cudie);
556 : }
557 : else
558 : {
559 : /* DW_AT_GNU_macros, DW_AT_macros */
560 : Dwarf_Word macoff;
561 269 : if (get_offset_from (cudie, DW_AT_GNU_macros, &macoff) != 0)
562 0 : return -1;
563 269 : offset = gnu_macros_getmacros_off (cudie->cu->dbg, macoff,
564 : callback, arg, offset, accept_0xff,
565 : cudie);
566 : }
567 :
568 535 : return token_from_offset (offset, accept_0xff);
569 : }
|