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
get_offset_from(Dwarf_Die * die,int name,Dwarf_Word * retp)43 get_offset_from (Dwarf_Die *die, int name, Dwarf_Word *retp)
44 {
45   /* Get the appropriate attribute.  */
46   Dwarf_Attribute attr;
47   if (INTUSE(dwarf_attr) (die, name, &attr) == NULL)
48     return -1;
49 
50   /* Offset into the corresponding section.  */
51   return INTUSE(dwarf_formudata) (&attr, retp);
52 }
53 
54 static int
macro_op_compare(const void * p1,const void * p2)55 macro_op_compare (const void *p1, const void *p2)
56 {
57   const Dwarf_Macro_Op_Table *t1 = (const Dwarf_Macro_Op_Table *) p1;
58   const Dwarf_Macro_Op_Table *t2 = (const Dwarf_Macro_Op_Table *) p2;
59 
60   if (t1->offset < t2->offset)
61     return -1;
62   if (t1->offset > t2->offset)
63     return 1;
64 
65   if (t1->sec_index < t2->sec_index)
66     return -1;
67   if (t1->sec_index > t2->sec_index)
68     return 1;
69 
70   return 0;
71 }
72 
73 static void
build_table(Dwarf_Macro_Op_Table * table,Dwarf_Macro_Op_Proto op_protos[static255])74 build_table (Dwarf_Macro_Op_Table *table,
75 	     Dwarf_Macro_Op_Proto op_protos[static 255])
76 {
77   unsigned ct = 0;
78   for (unsigned i = 1; i < 256; ++i)
79     if (op_protos[i - 1].forms != NULL)
80       table->table[table->opcodes[i - 1] = ct++] = op_protos[i - 1];
81     else
82       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
init_macinfo_table(void)96 init_macinfo_table (void)
97 {
98   MACRO_PROTO (p_udata_str, DW_FORM_udata, DW_FORM_string);
99   MACRO_PROTO (p_udata_udata, DW_FORM_udata, DW_FORM_udata);
100   MACRO_PROTO (p_none);
101 
102   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   Dwarf_Macro_Op_Table *macinfo_table = (void *) macinfo_data;
114   memset (macinfo_table, 0, sizeof macinfo_data);
115   build_table (macinfo_table, op_protos);
116   macinfo_table->sec_index = IDX_debug_macinfo;
117 }
118 
119 static Dwarf_Macro_Op_Table *
get_macinfo_table(Dwarf * dbg,Dwarf_Word macoff,Dwarf_Die * cudie)120 get_macinfo_table (Dwarf *dbg, Dwarf_Word macoff, Dwarf_Die *cudie)
121 {
122   assert (cudie != NULL);
123 
124   Dwarf_Attribute attr_mem, *attr
125     = INTUSE(dwarf_attr) (cudie, DW_AT_stmt_list, &attr_mem);
126   Dwarf_Off line_offset = (Dwarf_Off) -1;
127   if (attr != NULL)
128     if (unlikely (INTUSE(dwarf_formudata) (attr, &line_offset) != 0))
129       return NULL;
130 
131   Dwarf_Macro_Op_Table *table = libdw_alloc (dbg, Dwarf_Macro_Op_Table,
132 					     macinfo_data_size, 1);
133   memcpy (table, macinfo_data, macinfo_data_size);
134 
135   table->offset = macoff;
136   table->sec_index = IDX_debug_macinfo;
137   table->line_offset = line_offset;
138   table->is_64bit = cudie->cu->address_size == 8;
139   table->comp_dir = __libdw_getcompdir (cudie);
140 
141   return table;
142 }
143 
144 static Dwarf_Macro_Op_Table *
get_table_for_offset(Dwarf * dbg,Dwarf_Word macoff,const unsigned char * readp,const unsigned char * const endp,Dwarf_Die * cudie)145 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   const unsigned char *startp = readp;
151 
152   /* Request at least 3 bytes for header.  */
153   if (readp + 3 > endp)
154     {
155     invalid_dwarf:
156       __libdw_seterrno (DWARF_E_INVALID_DWARF);
157       return NULL;
158     }
159 
160   uint16_t version = read_2ubyte_unaligned_inc (dbg, readp);
161   if (version != 4)
162     {
163       __libdw_seterrno (DWARF_E_INVALID_VERSION);
164       return NULL;
165     }
166 
167   uint8_t flags = *readp++;
168   bool is_64bit = (flags & 0x1) != 0;
169 
170   Dwarf_Off line_offset = (Dwarf_Off) -1;
171   if ((flags & 0x2) != 0)
172     {
173       line_offset = read_addr_unaligned_inc (is_64bit ? 8 : 4, dbg, readp);
174       if (readp > endp)
175 	goto invalid_dwarf;
176     }
177   else if (cudie != NULL)
178     {
179       Dwarf_Attribute attr_mem, *attr
180 	= INTUSE(dwarf_attr) (cudie, DW_AT_stmt_list, &attr_mem);
181       if (attr != NULL)
182 	if (unlikely (INTUSE(dwarf_formudata) (attr, &line_offset) != 0))
183 	  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   MACRO_PROTO (p_udata_str, DW_FORM_udata, DW_FORM_string);
194   MACRO_PROTO (p_udata_strp, DW_FORM_udata, DW_FORM_strp);
195   MACRO_PROTO (p_udata_udata, DW_FORM_udata, DW_FORM_udata);
196   MACRO_PROTO (p_secoffset, DW_FORM_sec_offset);
197   MACRO_PROTO (p_none);
198 
199   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   if ((flags & 0x4) != 0)
213     {
214       unsigned count = *readp++;
215       for (unsigned i = 0; i < count; ++i)
216 	{
217 	  unsigned opcode = *readp++;
218 
219 	  Dwarf_Macro_Op_Proto e;
220 	  if (readp >= endp)
221 	    goto invalid;
222 	  get_uleb128 (e.nforms, readp, endp);
223 	  e.forms = readp;
224 	  op_protos[opcode - 1] = e;
225 
226 	  readp += e.nforms;
227 	  if (readp > endp)
228 	    {
229 	    invalid:
230 	      __libdw_seterrno (DWARF_E_INVALID_DWARF);
231 	      return NULL;
232 	    }
233 	}
234     }
235 
236   size_t ct = 0;
237   for (unsigned i = 1; i < 256; ++i)
238     if (op_protos[i - 1].forms != NULL)
239       ++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   assert (ct < 0xff);
245 
246   size_t macop_table_size = offsetof (Dwarf_Macro_Op_Table, table[ct]);
247 
248   Dwarf_Macro_Op_Table *table = libdw_alloc (dbg, Dwarf_Macro_Op_Table,
249 					     macop_table_size, 1);
250 
251   *table = (Dwarf_Macro_Op_Table) {
252     .offset = macoff,
253     .sec_index = IDX_debug_macro,
254     .line_offset = line_offset,
255     .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     .comp_dir = __libdw_getcompdir (cudie),
261   };
262   build_table (table, op_protos);
263 
264   return table;
265 }
266 
267 static Dwarf_Macro_Op_Table *
cache_op_table(Dwarf * dbg,int sec_index,Dwarf_Off macoff,const unsigned char * startp,const unsigned char * const endp,Dwarf_Die * cudie)268 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   Dwarf_Macro_Op_Table fake = { .offset = macoff, .sec_index = sec_index };
274   Dwarf_Macro_Op_Table **found = tfind (&fake, &dbg->macro_ops,
275 					macro_op_compare);
276   if (found != NULL)
277     return *found;
278 
279   Dwarf_Macro_Op_Table *table = sec_index == IDX_debug_macro
280     ? get_table_for_offset (dbg, macoff, startp, endp, cudie)
281     : get_macinfo_table (dbg, macoff, cudie);
282 
283   if (table == NULL)
284     return NULL;
285 
286   Dwarf_Macro_Op_Table **ret = tsearch (table, &dbg->macro_ops,
287 					macro_op_compare);
288   if (unlikely (ret == NULL))
289     {
290       __libdw_seterrno (DWARF_E_NOMEM);
291       return NULL;
292     }
293 
294   return *ret;
295 }
296 
297 static ptrdiff_t
read_macros(Dwarf * dbg,int sec_index,Dwarf_Off macoff,int (* callback)(Dwarf_Macro *,void *),void * arg,ptrdiff_t offset,bool accept_0xff,Dwarf_Die * cudie)298 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   Elf_Data *d = dbg->sectiondata[sec_index];
304   if (unlikely (d == NULL || d->d_buf == NULL))
305     {
306       __libdw_seterrno (DWARF_E_NO_ENTRY);
307       return -1;
308     }
309 
310   if (unlikely (macoff >= d->d_size))
311     {
312       __libdw_seterrno (DWARF_E_INVALID_DWARF);
313       return -1;
314     }
315 
316   const unsigned char *const startp = d->d_buf + macoff;
317   const unsigned char *const endp = d->d_buf + d->d_size;
318 
319   Dwarf_Macro_Op_Table *table = cache_op_table (dbg, sec_index, macoff,
320 						startp, endp, cudie);
321   if (table == NULL)
322     return -1;
323 
324   if (offset == 0)
325     offset = table->header_len;
326 
327   assert (offset >= 0);
328   assert (offset < endp - startp);
329   const unsigned char *readp = startp + offset;
330 
331   while (readp < endp)
332     {
333       unsigned int opcode = *readp++;
334       if (opcode == 0)
335 	/* Nothing more to do.  */
336 	return 0;
337 
338       if (unlikely (opcode == 0xff && ! accept_0xff))
339 	{
340 	  /* See comment below at dwarf_getmacros for explanation of
341 	     why we are doing this.  */
342 	  __libdw_seterrno (DWARF_E_INVALID_OPCODE);
343 	  return -1;
344 	}
345 
346       unsigned int idx = table->opcodes[opcode - 1];
347       if (idx == 0xff)
348 	{
349 	  __libdw_seterrno (DWARF_E_INVALID_OPCODE);
350 	  return -1;
351 	}
352 
353       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       Dwarf_CU fake_cu = {
359 	.dbg = dbg,
360 	.version = 4,
361 	.offset_size = table->is_64bit ? 8 : 4,
362 	.startp = (void *) startp + offset,
363 	.endp = (void *) endp,
364       };
365 
366       Dwarf_Attribute *attributes;
367       Dwarf_Attribute *attributesp = NULL;
368       Dwarf_Attribute nattributes[8];
369       if (unlikely (proto->nforms > 8))
370 	{
371 	  attributesp = malloc (sizeof (Dwarf_Attribute) * proto->nforms);
372 	  if (attributesp == NULL)
373 	    {
374 	      __libdw_seterrno (DWARF_E_NOMEM);
375 	      return -1;
376 	    }
377 	  attributes = attributesp;
378 	}
379       else
380 	attributes = &nattributes[0];
381 
382       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 	  attributes[i].code = DW_AT_GNU_macros;
388 	  attributes[i].form = proto->forms[i];
389 	  attributes[i].valp = (void *) readp;
390 	  attributes[i].cu = &fake_cu;
391 
392 	  size_t len = __libdw_form_val_len (&fake_cu, proto->forms[i], readp);
393 	  if (unlikely (len == (size_t) -1))
394 	    {
395 	      free (attributesp);
396 	      return -1;
397 	    }
398 
399 	  readp += len;
400 	}
401 
402       Dwarf_Macro macro = {
403 	.table = table,
404 	.opcode = opcode,
405 	.attributes = attributes,
406       };
407 
408       int res = callback (&macro, arg);
409       if (unlikely (attributesp != NULL))
410 	free (attributesp);
411 
412       if (res != DWARF_CB_OK)
413 	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
token_from_offset(ptrdiff_t offset,bool accept_0xff)436 token_from_offset (ptrdiff_t offset, bool accept_0xff)
437 {
438   if (offset == -1 || offset == 0)
439     return offset;
440 
441   /* Make sure the offset didn't overflow into the flag bit.  */
442   if ((offset & DWARF_GETMACROS_START) != 0)
443     {
444       __libdw_seterrno (DWARF_E_TOO_BIG);
445       return -1;
446     }
447 
448   if (accept_0xff)
449     offset |= DWARF_GETMACROS_START;
450 
451   return offset;
452 }
453 
454 static ptrdiff_t
offset_from_token(ptrdiff_t token,bool * accept_0xffp)455 offset_from_token (ptrdiff_t token, bool *accept_0xffp)
456 {
457   *accept_0xffp = (token & DWARF_GETMACROS_START) != 0;
458   token &= ~DWARF_GETMACROS_START;
459 
460   return token;
461 }
462 
463 static ptrdiff_t
gnu_macros_getmacros_off(Dwarf * dbg,Dwarf_Off macoff,int (* callback)(Dwarf_Macro *,void *),void * arg,ptrdiff_t offset,bool accept_0xff,Dwarf_Die * cudie)464 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   assert (offset >= 0);
470 
471   if (macoff >= dbg->sectiondata[IDX_debug_macro]->d_size)
472     {
473       __libdw_seterrno (DWARF_E_INVALID_OFFSET);
474       return -1;
475     }
476 
477   return read_macros (dbg, IDX_debug_macro, macoff,
478 		      callback, arg, offset, accept_0xff, cudie);
479 }
480 
481 static ptrdiff_t
macro_info_getmacros_off(Dwarf * dbg,Dwarf_Off macoff,int (* callback)(Dwarf_Macro *,void *),void * arg,ptrdiff_t offset,Dwarf_Die * cudie)482 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   assert (offset >= 0);
487 
488   return read_macros (dbg, IDX_debug_macinfo, macoff,
489 		      callback, arg, offset, true, cudie);
490 }
491 
492 ptrdiff_t
dwarf_getmacros_off(Dwarf * dbg,Dwarf_Off macoff,int (* callback)(Dwarf_Macro *,void *),void * arg,ptrdiff_t token)493 dwarf_getmacros_off (Dwarf *dbg, Dwarf_Off macoff,
494 		     int (*callback) (Dwarf_Macro *, void *),
495 		     void *arg, ptrdiff_t token)
496 {
497   if (dbg == NULL)
498     {
499       __libdw_seterrno (DWARF_E_NO_DWARF);
500       return -1;
501     }
502 
503   bool accept_0xff;
504   ptrdiff_t offset = offset_from_token (token, &accept_0xff);
505   assert (accept_0xff);
506 
507   offset = gnu_macros_getmacros_off (dbg, macoff, callback, arg, offset,
508 				     accept_0xff, NULL);
509 
510   return token_from_offset (offset, accept_0xff);
511 }
512 
513 ptrdiff_t
dwarf_getmacros(Dwarf_Die * cudie,int (* callback)(Dwarf_Macro *,void *),void * arg,ptrdiff_t token)514 dwarf_getmacros (Dwarf_Die *cudie, int (*callback) (Dwarf_Macro *, void *),
515 		 void *arg, ptrdiff_t token)
516 {
517   if (cudie == NULL)
518     {
519       __libdw_seterrno (DWARF_E_NO_DWARF);
520       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   ptrdiff_t offset = offset_from_token (token, &accept_0xff);
547 
548   /* DW_AT_macro_info */
549   if (dwarf_hasattr (cudie, DW_AT_macro_info))
550     {
551       Dwarf_Word macoff;
552       if (get_offset_from (cudie, DW_AT_macro_info, &macoff) != 0)
553 	return -1;
554       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       if (get_offset_from (cudie, DW_AT_GNU_macros, &macoff) != 0)
562 	return -1;
563       offset = gnu_macros_getmacros_off (cudie->cu->dbg, macoff,
564 					 callback, arg, offset, accept_0xff,
565 					 cudie);
566     }
567 
568   return token_from_offset (offset, accept_0xff);
569 }
570