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 */
dwarf_get_harmless_error_list(Dwarf_Debug dbg,unsigned count,const char ** errmsg_ptrs_array,unsigned * errs_count)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
safe_strncpy(char * targ,char * src,unsigned spaceavail)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. */
dwarf_insert_harmless_error(Dwarf_Debug dbg,char * newerror)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 */
dwarf_set_harmless_error_list_size(Dwarf_Debug dbg,unsigned maxcount)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
dwarf_harmless_init(struct Dwarf_Harmless_s * dhp,unsigned size)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
dwarf_harmless_cleanout(struct Dwarf_Harmless_s * dhp)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