xref: /illumos-gate/usr/src/lib/libdwarf/common/dwarf_harmless.c (revision b12258b69ac245658b0ca5ae070b3ff004186148)
1 /*
2 
3   Copyright (C) 2010 David Anderson. All Rights Reserved.
4 
5   This program is free software; you can redistribute it and/or modify it
6   under the terms of version 2.1 of the GNU Lesser General Public License
7   as published by the Free Software Foundation.
8 
9   This program is distributed in the hope that it would be useful, but
10   WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13   Further, this software is distributed without any warranty that it is
14   free of the rightful claim of any third person regarding infringement
15   or the like.  Any license provided herein, whether implied or
16   otherwise, applies only to this software file.  Patent licenses, if
17   any, provided herein do not apply to combinations of this program with
18   other software, or any other product whatsoever.
19 
20   You should have received a copy of the GNU Lesser General Public
21   License along with this program; if not, write the Free Software
22   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
23   USA.
24 
25 */
26 
27 /*
28         This  implements _dwarf_insert_harmless_error
29         and related helper functions for recording
30         compiler errors that need not make the input
31         unusable.
32 
33         Applications can use dwarf_get_harmless_error_list to
34         find (and possibly print) a warning about such errors.
35 
36         The initial error reported here is
37         DW_DLE_DEBUG_FRAME_LENGTH_NOT_MULTIPLE which was a
38         bug in a specific compiler.
39 
40         It is a fixed length circular list to constrain
41         the space used for errors.
42 
43         The assumption is that these errors are exceedingly
44         rare, and indicate a broken compiler (the one that
45         produced the object getting the error(s)).
46 
47         dh_maxcount is recorded internally as 1 greater than
48         requested.  Hiding the fact we always leave one
49         slot unused (at least).   So a user request for
50         N slots really gives the user N usable slots.
51 */
52 
53 
54 
55 #include "config.h"
56 #include "dwarf_incl.h"
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include "dwarf_frame.h"
60 #include "dwarf_harmless.h"
61 
62 
63 /* The pointers returned here through errmsg_ptrs_array
64    become invalidated by any call to libdwarf. Any call.
65 */
66 int dwarf_get_harmless_error_list(Dwarf_Debug dbg,
67     unsigned  count,
68     const char ** errmsg_ptrs_array,
69     unsigned * errs_count)
70 {
71     struct Dwarf_Harmless_s *dhp = &dbg->de_harmless_errors;
72     if(!dhp->dh_errors) {
73         dhp->dh_errs_count = 0;
74         return DW_DLV_NO_ENTRY;
75     }
76     if(dhp->dh_errs_count == 0) {
77         return DW_DLV_NO_ENTRY;
78     }
79     if(errs_count) {
80         *errs_count = dhp->dh_errs_count;
81     }
82     if(count) {
83         /* NULL terminate the array of pointers */
84         --count;
85         errmsg_ptrs_array[count] = 0;
86 
87         if(dhp->dh_next_to_use != dhp->dh_first) {
88             unsigned i = 0;
89             unsigned cur = dhp->dh_first;
90             for(i = 0;  cur != dhp->dh_next_to_use; ++i) {
91                 if(i >= count ) {
92                     /* All output spaces are used. */
93                     break;
94                 }
95                 errmsg_ptrs_array[i] = dhp->dh_errors[cur];
96                 cur = (cur +1) % dhp->dh_maxcount;
97             }
98             errmsg_ptrs_array[i] = 0;
99         }
100     }
101     dhp->dh_next_to_use = 0;
102     dhp->dh_first = 0;
103     dhp->dh_errs_count = 0;
104     return DW_DLV_OK;
105 }
106 
107 /* strncpy does not null-terminate, this does it. */
108 static void
109 safe_strncpy(char *targ, char *src, unsigned spaceavail)
110 {
111     unsigned goodcount = spaceavail-1;
112     if(spaceavail < 1) {
113         return; /* impossible */
114     }
115     strncpy(targ,src,goodcount);
116     targ[goodcount] = 0;
117 }
118 
119 /* Insertion made public is only for testing the harmless error code,
120    it is not necessarily useful for libdwarf client code aside
121    from code testing libdwarf. */
122 void dwarf_insert_harmless_error(Dwarf_Debug dbg,
123     char *newerror)
124 {
125     struct Dwarf_Harmless_s *dhp = &dbg->de_harmless_errors;
126     unsigned next = 0;
127     unsigned cur = dhp->dh_next_to_use;
128     char *msgspace;
129     if(!dhp->dh_errors) {
130         dhp->dh_errs_count++;
131         return;
132     }
133     msgspace = dhp->dh_errors[cur];
134     safe_strncpy(msgspace, newerror,DW_HARMLESS_ERROR_MSG_STRING_SIZE);
135     next = (cur+1) % dhp->dh_maxcount;
136     dhp->dh_errs_count++;
137     dhp->dh_next_to_use = next;
138     if (dhp->dh_next_to_use ==  dhp->dh_first) {
139         /* Array is full set full invariant. */
140         dhp->dh_first = (dhp->dh_first+1) % dhp->dh_maxcount;
141     }
142 }
143 
144 /* The size of the circular list of strings may be set
145     and reset as desired. Returns the previous size of
146     the list. If the list is shortened excess error entries
147     are simply dropped.
148     If the reallocation fails the list size is left unchanged.
149     Do not make this a long list!
150 
151     Remember the maxcount we record is 1 > the user count,
152     so we adjust it so it looks like the user count.
153 */
154 unsigned dwarf_set_harmless_error_list_size(Dwarf_Debug dbg,
155     unsigned maxcount )
156 {
157     struct Dwarf_Harmless_s *dhp = &dbg->de_harmless_errors;
158     unsigned prevcount = dhp->dh_maxcount;
159     if(maxcount != 0) {
160         ++maxcount;
161         if(maxcount != dhp->dh_maxcount) {
162             /* Assign transfers 'ownership' of the malloc areas
163                to oldarray. */
164             struct Dwarf_Harmless_s oldarray = *dhp;
165             /* Do not double increment the max, the init() func
166                increments it too. */
167             dwarf_harmless_init(dhp,maxcount-1);
168             if(oldarray.dh_next_to_use != oldarray.dh_first) {
169                 unsigned i = 0;
170                 for(i = oldarray.dh_first; i != oldarray.dh_next_to_use;
171                      i = (i+1)%oldarray.dh_maxcount) {
172                     dwarf_insert_harmless_error(dbg,oldarray.dh_errors[i]);
173                 }
174                 if( oldarray.dh_errs_count > dhp->dh_errs_count) {
175                     dhp->dh_errs_count = oldarray.dh_errs_count;
176                 }
177             }
178             dwarf_harmless_cleanout(&oldarray);
179         }
180     }
181     return prevcount-1;
182 }
183 
184 void
185 dwarf_harmless_init(struct Dwarf_Harmless_s *dhp,unsigned size)
186 {
187     unsigned i = 0;
188     memset(dhp,0,sizeof(*dhp));
189     dhp->dh_maxcount = size +1;
190     dhp->dh_errors = (char **)malloc(sizeof( char *) *dhp->dh_maxcount);
191     if (!dhp->dh_errors) {
192         dhp->dh_maxcount = 0;
193         return;
194     }
195 
196     for(i = 0; i < dhp->dh_maxcount; ++i) {
197         char *newstr =
198              (char *)malloc(DW_HARMLESS_ERROR_MSG_STRING_SIZE);
199         dhp->dh_errors[i] = newstr;
200         if(!newstr) {
201             dhp->dh_maxcount = 0;
202             /* Let it leak, the leak is a constrained amount. */
203             dhp->dh_errors = 0;
204             return;
205         }
206         /* We make the string content well-defined by an initial
207            NUL byte, but this is not really necessary. */
208         newstr[0] = 0;
209     }
210 }
211 
212 void
213 dwarf_harmless_cleanout(struct Dwarf_Harmless_s *dhp)
214 {
215      unsigned i = 0;
216      if(!dhp->dh_errors) {
217          return;
218      }
219      for(i = 0; i < dhp->dh_maxcount; ++i) {
220          free(dhp->dh_errors[i]);
221      }
222      free(dhp->dh_errors);
223      dhp->dh_errors = 0;
224      dhp->dh_maxcount = 0;
225 }
226 
227