xref: /illumos-gate/usr/src/lib/libdwarf/common/dwarf_macro.c (revision 4d9fdb46b215739778ebc12079842c9905586999)
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 *
dwarf_find_macro_value_start(char * str)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
free_macro_stack(Dwarf_Debug dbg,struct macro_stack_s * ms)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
_dwarf_reset_index_macro_stack(struct macro_stack_s * ms)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
_dwarf_macro_stack_push_index(Dwarf_Debug dbg,Dwarf_Signed indx,struct macro_stack_s * ms)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
_dwarf_macro_stack_pop_index(struct macro_stack_s * ms)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
dwarf_get_macro_details(Dwarf_Debug dbg,Dwarf_Off macro_offset,Dwarf_Unsigned maximum_count,Dwarf_Signed * entry_count,Dwarf_Macro_Details ** details,Dwarf_Error * error)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