xref: /illumos-gate/usr/src/lib/libdwarf/common/dwarf_macro.c (revision 6a8fa7ea16d9870b21c82af67a2053cb47ed1fb4)
1  /*
2    Copyright (C) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
3    Portions Copyright (C) 2007-2019 David Anderson. All Rights Reserved.
4    Portions Copyright 2012 SN Systems Ltd. All rights reserved.
5  
6    This program is free software; you can redistribute it and/or modify it
7    under the terms of version 2.1 of the GNU Lesser General Public License
8    as published by the Free Software Foundation.
9  
10    This program is distributed in the hope that it would be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13  
14    Further, this software is distributed without any warranty that it is
15    free of the rightful claim of any third person regarding infringement
16    or the like.  Any license provided herein, whether implied or
17    otherwise, applies only to this software file.  Patent licenses, if
18    any, provided herein do not apply to combinations of this program with
19    other software, or any other product whatsoever.
20  
21    You should have received a copy of the GNU Lesser General Public
22    License along with this program; if not, write the Free Software
23    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
24    USA.
25  
26  */
27  
28  #include "config.h"
29  #include <stdio.h>
30  #include <limits.h>
31  #ifdef HAVE_STDLIB_H
32  #include <stdlib.h>
33  #endif /* HAVE_STDLIB_H */
34  #include "dwarf_incl.h"
35  #include "dwarf_alloc.h"
36  #include "dwarf_error.h"
37  #include "dwarf_util.h"
38  #include "dwarf_macro.h"
39  
40  
41  #define LEFTPAREN '('
42  #define RIGHTPAREN ')'
43  #define SPACE ' '
44  
45  /*  Given the dwarf macro string, return a pointer to
46      the value.  Returns pointer to 0 byte at end of string
47      if no value found (meaning the value is the empty string).
48  
49      Only understands well-formed dwarf macinfo strings.
50  */
51  char *
52  dwarf_find_macro_value_start(char *str)
53  {
54      char *lcp;
55      int funclike = 0;
56  
57      for (lcp = str; *lcp; ++lcp) {
58          switch (*lcp) {
59          case LEFTPAREN:
60              funclike = 1;
61              break;
62          case RIGHTPAREN:
63              /* lcp+1 must be a space, and following char is the value */
64              return lcp + 2;
65          case SPACE:
66              /*  We allow extraneous spaces inside macro parameter **
67                  list, just in case... This is not really needed. */
68              if (!funclike) {
69                  return lcp + 1;
70              }
71              break;
72          }
73      }
74      /*  Never found value: returns pointer to the 0 byte at end of
75          string. */
76      return lcp;
77  
78  }
79  
80  
81  /*
82     Try to keep fileindex correct in every Macro_Details
83     record by tracking file starts and ends.
84     Uses high water mark: space reused, not freed.
85     Presumption is that this makes sense for most uses.
86     STARTERMAX is set so that the array need not be expanded for
87     most files: it is the initial include file depth.
88  */
89  struct macro_stack_s {
90      Dwarf_Signed *st_base;
91      long st_max;
92      long st_next_to_use;
93      int  st_was_fault;
94  };
95  
96  static void _dwarf_reset_index_macro_stack(struct macro_stack_s *ms);
97  static void
98  free_macro_stack(Dwarf_Debug dbg, struct macro_stack_s *ms)
99  {
100      dwarf_dealloc(dbg,ms->st_base,DW_DLA_STRING);
101      _dwarf_reset_index_macro_stack(ms);
102  }
103  
104  #define STARTERMAX 10
105  static void
106  _dwarf_reset_index_macro_stack(struct macro_stack_s *ms)
107  {
108      ms->st_base = 0;
109      ms->st_max = 0;
110      ms->st_next_to_use = 0;
111      ms->st_was_fault = 0;
112  }
113  static int
114  _dwarf_macro_stack_push_index(Dwarf_Debug dbg, Dwarf_Signed indx,
115      struct macro_stack_s *ms)
116  {
117  
118      if (!ms->st_max || ms->st_next_to_use >= ms->st_max) {
119          long new_size = ms->st_max;
120          Dwarf_Signed *newbase = 0;
121  
122          if (!new_size) {
123              new_size = STARTERMAX;
124          }
125          new_size = new_size * 2;
126          newbase =
127              (Dwarf_Signed *)_dwarf_get_alloc(dbg, DW_DLA_STRING,
128                  new_size * sizeof(Dwarf_Signed));
129          if (!newbase) {
130              /* just leave the old array in place */
131              ms->st_was_fault = 1;
132              return DW_DLV_ERROR;
133          }
134          if (ms->st_base) {
135              memcpy(newbase, ms->st_base,
136                  ms->st_next_to_use * sizeof(Dwarf_Signed));
137              dwarf_dealloc(dbg, ms->st_base, DW_DLA_STRING);
138          }
139          ms->st_base = newbase;
140          ms->st_max = new_size;
141      }
142      ms->st_base[ms->st_next_to_use] = indx;
143      ++ms->st_next_to_use;
144      return DW_DLV_OK;
145  }
146  
147  static Dwarf_Signed
148  _dwarf_macro_stack_pop_index(struct macro_stack_s *ms)
149  {
150      if (ms->st_was_fault) {
151          return -1;
152      }
153      if (ms->st_next_to_use > 0) {
154          ms->st_next_to_use--;
155          return (ms->st_base[ms->st_next_to_use]);
156      } else {
157          ms->st_was_fault = 1;
158      }
159      return -1;
160  }
161  
162  /*  Starting at macro_offset in .debug_macinfo,
163      if maximum_count is 0, treat as if it is infinite.
164      get macro data up thru
165      maximum_count entries or the end of a compilation
166      unit's entries (whichever comes first).
167  
168      .debug_macinfo never appears in a .dwp Package File.
169      So offset adjustment for such is not needed.
170  */
171  
172  int
173  dwarf_get_macro_details(Dwarf_Debug dbg,
174      Dwarf_Off macro_offset,
175      Dwarf_Unsigned maximum_count,
176      Dwarf_Signed * entry_count,
177      Dwarf_Macro_Details ** details,
178      Dwarf_Error * error)
179  {
180      Dwarf_Small *macro_base = 0;
181      Dwarf_Small *macro_end = 0;
182      Dwarf_Small *pnext = 0;
183      Dwarf_Unsigned endloc = 0;
184      unsigned char uc = 0;
185      unsigned long depth = 0;
186          /* By section 6.3.2 Dwarf3 draft 8/9,
187          the base file should appear as
188          DW_MACINFO_start_file. See
189          http://gcc.gnu.org/ml/gcc-bugs/2005-02/msg03442.html
190          on "[Bug debug/20253] New: [3.4/4.0 regression]:
191          Macro debug info broken due to lexer change" for how
192          gcc is broken in some versions. We no longer use
193          depth as a stopping point, it's not needed as a
194          stopping point anyway.  */
195      int res = 0;
196      /* count space used by strings */
197      unsigned long str_space = 0;
198      int done = 0;
199      unsigned long space_needed = 0;
200      unsigned long string_offset = 0;
201      Dwarf_Small *return_data = 0;
202      Dwarf_Small *pdata = 0;
203      unsigned long final_count = 0;
204      Dwarf_Signed fileindex = -1;
205      Dwarf_Small *latest_str_loc = 0;
206      struct macro_stack_s msdata;
207  
208      unsigned long count = 0;
209      unsigned long max_count = (unsigned long) maximum_count;
210  
211      _dwarf_reset_index_macro_stack(&msdata);
212      if (dbg == NULL) {
213          _dwarf_error(NULL, error, DW_DLE_DBG_NULL);
214          free_macro_stack(dbg,&msdata);
215          return (DW_DLV_ERROR);
216      }
217  
218      res = _dwarf_load_section(dbg, &dbg->de_debug_macinfo,error);
219      if (res != DW_DLV_OK) {
220          free_macro_stack(dbg,&msdata);
221          return res;
222      }
223      if (!dbg->de_debug_abbrev.dss_size) {
224          free_macro_stack(dbg,&msdata);
225          return (DW_DLV_NO_ENTRY);
226      }
227  
228      macro_base = dbg->de_debug_macinfo.dss_data;
229      if (macro_base == NULL) {
230          free_macro_stack(dbg,&msdata);
231          return (DW_DLV_NO_ENTRY);
232      }
233      if (macro_offset >= dbg->de_debug_macinfo.dss_size) {
234          free_macro_stack(dbg,&msdata);
235          return (DW_DLV_NO_ENTRY);
236      }
237      macro_end = macro_base + dbg->de_debug_macinfo.dss_size;
238      /*   FIXME debugfission is NOT handled here.  */
239  
240      pnext = macro_base + macro_offset;
241      if (maximum_count == 0) {
242          max_count = ULONG_MAX;
243      }
244  
245  
246      /* how many entries and how much space will they take? */
247  
248      endloc = (pnext - macro_base);
249      if (endloc >= dbg->de_debug_macinfo.dss_size) {
250          if (endloc == dbg->de_debug_macinfo.dss_size) {
251              /* normal: found last entry */
252              free_macro_stack(dbg,&msdata);
253              return DW_DLV_NO_ENTRY;
254          }
255          _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_LENGTH_BAD);
256          free_macro_stack(dbg,&msdata);
257          return (DW_DLV_ERROR);
258      }
259      for (count = 0; !done && count < max_count; ++count) {
260          unsigned long slen = 0;
261  
262          /* Set but not used */
263          UNUSEDARG Dwarf_Unsigned utemp = 0;
264  
265          uc = *pnext;
266          ++pnext;                /* get past the type code */
267          switch (uc) {
268          case DW_MACINFO_define:
269          case DW_MACINFO_undef:
270              /* line, string */
271          case DW_MACINFO_vendor_ext:
272              /* number, string */
273              DECODE_LEB128_UWORD_CK(pnext,utemp,dbg,error,
274                  macro_end);
275              if (((Dwarf_Unsigned)(pnext - macro_base)) >=
276                  dbg->de_debug_macinfo.dss_size) {
277                  free_macro_stack(dbg,&msdata);
278                  _dwarf_error(dbg, error,
279                      DW_DLE_DEBUG_MACRO_INCONSISTENT);
280                  return (DW_DLV_ERROR);
281              }
282              res = _dwarf_check_string_valid(dbg,
283                  macro_base,pnext,macro_end,
284                  DW_DLE_MACINFO_STRING_BAD,error);
285              if (res != DW_DLV_OK) {
286                  return res;
287              }
288              slen = strlen((char *) pnext) + 1;
289              pnext += slen;
290              if (((Dwarf_Unsigned)(pnext - macro_base)) >=
291                  dbg->de_debug_macinfo.dss_size) {
292                  free_macro_stack(dbg,&msdata);
293                  _dwarf_error(dbg, error,
294                      DW_DLE_DEBUG_MACRO_INCONSISTENT);
295                  return (DW_DLV_ERROR);
296              }
297              str_space += slen;
298              break;
299          case DW_MACINFO_start_file:
300              /* line, file index */
301              DECODE_LEB128_UWORD_CK(pnext,utemp,dbg,error,
302                  macro_end);
303              if (((Dwarf_Unsigned)(pnext - macro_base)) >=
304                  dbg->de_debug_macinfo.dss_size) {
305                  free_macro_stack(dbg,&msdata);
306                  _dwarf_error(dbg, error,
307                      DW_DLE_DEBUG_MACRO_INCONSISTENT);
308                  return (DW_DLV_ERROR);
309              }
310              DECODE_LEB128_UWORD_CK(pnext,utemp,dbg,error,
311                  macro_end);
312              if (((Dwarf_Unsigned)(pnext - macro_base)) >=
313                  dbg->de_debug_macinfo.dss_size) {
314                  free_macro_stack(dbg,&msdata);
315                  _dwarf_error(dbg, error,
316                      DW_DLE_DEBUG_MACRO_INCONSISTENT);
317                  return (DW_DLV_ERROR);
318              }
319              ++depth;
320              break;
321  
322          case DW_MACINFO_end_file:
323              if (--depth == 0) {
324                  /*  done = 1; no, do not stop here, at least one gcc had
325                      the wrong depth settings in the gcc 3.4 timeframe. */
326              }
327              /* no string or number here */
328              break;
329          case 0:
330              /* end of cu's entries */
331              done = 1;
332              break;
333          default:
334              free_macro_stack(dbg,&msdata);
335              _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_INCONSISTENT);
336              return (DW_DLV_ERROR);
337              /* bogus macinfo! */
338          }
339  
340          endloc = (pnext - macro_base);
341          if (endloc == dbg->de_debug_macinfo.dss_size) {
342              done = 1;
343          } else if (endloc > dbg->de_debug_macinfo.dss_size) {
344              _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_LENGTH_BAD);
345              free_macro_stack(dbg,&msdata);
346              return (DW_DLV_ERROR);
347          }
348      }
349      /*  ASSERT: The above loop will never let us get here
350          with count < 1. No need to test for a zero count.
351  
352          We have 'count' array entries to allocate and
353          str_space bytes of string space to provide for. */
354  
355      string_offset = count * sizeof(Dwarf_Macro_Details);
356  
357      /* extra 2 not really needed */
358      space_needed = string_offset + str_space + 2;
359      return_data = pdata =
360          (Dwarf_Small *)_dwarf_get_alloc(dbg, DW_DLA_STRING, space_needed);
361      latest_str_loc = pdata + string_offset;
362      if (pdata == 0) {
363          free_macro_stack(dbg,&msdata);
364          _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_MALLOC_SPACE);
365          return (DW_DLV_ERROR);
366      }
367      pnext = macro_base + macro_offset;
368  
369      done = 0;
370  
371      /* A series ends with a type code of 0. */
372  
373      for (final_count = 0; !done && final_count < count; ++final_count) {
374          unsigned long slen = 0;
375          Dwarf_Unsigned v1 = 0;
376          Dwarf_Macro_Details *pdmd = (Dwarf_Macro_Details *) (pdata +
377              (final_count * sizeof (Dwarf_Macro_Details)));
378  
379          endloc = (pnext - macro_base);
380          if (endloc > dbg->de_debug_macinfo.dss_size) {
381              free_macro_stack(dbg,&msdata);
382              _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_LENGTH_BAD);
383              return (DW_DLV_ERROR);
384          }
385          uc = *pnext;
386          pdmd->dmd_offset = (pnext - macro_base);
387          pdmd->dmd_type = uc;
388          pdmd->dmd_fileindex = fileindex;
389          pdmd->dmd_lineno = 0;
390          pdmd->dmd_macro = 0;
391          ++pnext;                /* get past the type code */
392          switch (uc) {
393          case DW_MACINFO_define:
394          case DW_MACINFO_undef:
395              /* line, string */
396          case DW_MACINFO_vendor_ext:
397              /* number, string */
398              DECODE_LEB128_UWORD_CK(pnext,v1,dbg,error,
399                  macro_end);
400              pdmd->dmd_lineno = v1;
401  
402              if (((Dwarf_Unsigned)(pnext - macro_base)) >=
403                  dbg->de_debug_macinfo.dss_size) {
404                  free_macro_stack(dbg,&msdata);
405                  dwarf_dealloc(dbg, return_data, DW_DLA_STRING);
406                  _dwarf_error(dbg, error,
407                      DW_DLE_DEBUG_MACRO_INCONSISTENT);
408                  return (DW_DLV_ERROR);
409              }
410              res = _dwarf_check_string_valid(dbg,
411                  macro_base,pnext,macro_end,
412                  DW_DLE_MACINFO_STRING_BAD,error);
413              if (res != DW_DLV_OK) {
414                  return res;
415              }
416              slen = strlen((char *) pnext) + 1;
417              strcpy((char *) latest_str_loc, (char *) pnext);
418              pdmd->dmd_macro = (char *) latest_str_loc;
419              latest_str_loc += slen;
420              pnext += slen;
421              if (((Dwarf_Unsigned)(pnext - macro_base)) >=
422                  dbg->de_debug_macinfo.dss_size) {
423                  free_macro_stack(dbg,&msdata);
424                  dwarf_dealloc(dbg, return_data, DW_DLA_STRING);
425                  _dwarf_error(dbg, error,
426                      DW_DLE_DEBUG_MACRO_INCONSISTENT);
427                  return (DW_DLV_ERROR);
428              }
429              break;
430          case DW_MACINFO_start_file:
431              /* Line, file index */
432              DECODE_LEB128_UWORD_CK(pnext,v1,dbg,error,
433                  macro_end);
434              pdmd->dmd_lineno = v1;
435              if (((Dwarf_Unsigned)(pnext - macro_base)) >=
436                  dbg->de_debug_macinfo.dss_size) {
437                  free_macro_stack(dbg,&msdata);
438                  dwarf_dealloc(dbg, return_data, DW_DLA_STRING);
439                  _dwarf_error(dbg, error,
440                      DW_DLE_DEBUG_MACRO_INCONSISTENT);
441                  return (DW_DLV_ERROR);
442              }
443              DECODE_LEB128_UWORD_CK(pnext,v1,dbg,error,
444                  macro_end);
445              pdmd->dmd_fileindex = v1;
446              (void) _dwarf_macro_stack_push_index(dbg, fileindex,
447                  &msdata);
448              /*  We ignore the error, we just let fileindex ** be -1 when
449                  we pop this one. */
450              fileindex = v1;
451              if (((Dwarf_Unsigned)(pnext - macro_base)) >=
452                  dbg->de_debug_macinfo.dss_size) {
453                  free_macro_stack(dbg,&msdata);
454                  dwarf_dealloc(dbg, return_data, DW_DLA_STRING);
455                  _dwarf_error(dbg, error,
456                      DW_DLE_DEBUG_MACRO_INCONSISTENT);
457                  return (DW_DLV_ERROR);
458              }
459              break;
460  
461          case DW_MACINFO_end_file:
462              fileindex = _dwarf_macro_stack_pop_index(&msdata);
463              break;              /* no string or number here */
464          case 0:
465              /* Type code of 0 means the end of cu's entries. */
466              done = 1;
467              break;
468          default:
469              /* Bogus macinfo! */
470              dwarf_dealloc(dbg, return_data, DW_DLA_STRING);
471              free_macro_stack(dbg,&msdata);
472              _dwarf_error(dbg, error, DW_DLE_DEBUG_MACRO_INCONSISTENT);
473              return (DW_DLV_ERROR);
474          }
475      }
476      *entry_count = count;
477      *details = (Dwarf_Macro_Details *) return_data;
478      free_macro_stack(dbg,&msdata);
479      return DW_DLV_OK;
480  }
481