1 /*
2 Copyright (C) 2010-2018 David Anderson. All Rights Reserved.
3 Portions Copyright 2012 SN Systems Ltd. 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 /* This implements _dwarf_insert_harmless_error
28 and related helper functions for recording
29 compiler errors that need not make the input
30 unusable.
31
32 Applications can use dwarf_get_harmless_error_list to
33 find (and possibly print) a warning about such errors.
34
35 The initial error reported here is
36 DW_DLE_DEBUG_FRAME_LENGTH_NOT_MULTIPLE which was a
37 bug in a specific compiler.
38
39 It is a fixed length circular list to constrain
40 the space used for errors.
41
42 The assumption is that these errors are exceedingly
43 rare, and indicate a broken compiler (the one that
44 produced the object getting the error(s)).
45
46 dh_maxcount is recorded internally as 1 greater than
47 requested. Hiding the fact we always leave one
48 slot unused (at least). So a user request for
49 N slots really gives the user N usable slots. */
50
51
52
53 #include "config.h"
54 #include "dwarf_incl.h"
55 #include <stdio.h>
56 #ifdef HAVE_STDLIB_H
57 #include <stdlib.h>
58 #endif /* HAVE_STDLIB_H */
59 #ifdef HAVE_MALLOC_H
60 /* Useful include for some Windows compilers. */
61 #include <malloc.h>
62 #endif /* HAVE_MALLOC_H */
63 #include "dwarf_frame.h"
64 #include "dwarf_harmless.h"
65
66
67 /* The pointers returned here through errmsg_ptrs_array
68 become invalidated by any call to libdwarf. Any call.
69 */
dwarf_get_harmless_error_list(Dwarf_Debug dbg,unsigned count,const char ** errmsg_ptrs_array,unsigned * errs_count)70 int dwarf_get_harmless_error_list(Dwarf_Debug dbg,
71 unsigned count,
72 const char ** errmsg_ptrs_array,
73 unsigned * errs_count)
74 {
75 struct Dwarf_Harmless_s *dhp = &dbg->de_harmless_errors;
76 if (!dhp->dh_errors) {
77 dhp->dh_errs_count = 0;
78 return DW_DLV_NO_ENTRY;
79 }
80 if (dhp->dh_errs_count == 0) {
81 return DW_DLV_NO_ENTRY;
82 }
83 if (errs_count) {
84 *errs_count = dhp->dh_errs_count;
85 }
86 if (count) {
87 /* NULL terminate the array of pointers */
88 --count;
89 errmsg_ptrs_array[count] = 0;
90
91 if (dhp->dh_next_to_use != dhp->dh_first) {
92 unsigned i = 0;
93 unsigned cur = dhp->dh_first;
94 for (i = 0; cur != dhp->dh_next_to_use; ++i) {
95 if (i >= count ) {
96 /* All output spaces are used. */
97 break;
98 }
99 errmsg_ptrs_array[i] = dhp->dh_errors[cur];
100 cur = (cur +1) % dhp->dh_maxcount;
101 }
102 errmsg_ptrs_array[i] = 0;
103 }
104 }
105 dhp->dh_next_to_use = 0;
106 dhp->dh_first = 0;
107 dhp->dh_errs_count = 0;
108 return DW_DLV_OK;
109 }
110
111 /* strncpy does not null-terminate, this does it. */
112 static void
safe_strncpy(char * targ,char * src,unsigned spaceavail)113 safe_strncpy(char *targ, char *src, unsigned spaceavail)
114 {
115 unsigned goodcount = spaceavail-1;
116 if (spaceavail < 1) {
117 return; /* impossible */
118 }
119 strncpy(targ,src,goodcount);
120 targ[goodcount] = 0;
121 }
122
123 /* Insertion made public is only for testing the harmless error code,
124 it is not necessarily useful for libdwarf client code aside
125 from code testing libdwarf. */
dwarf_insert_harmless_error(Dwarf_Debug dbg,char * newerror)126 void dwarf_insert_harmless_error(Dwarf_Debug dbg,
127 char *newerror)
128 {
129 struct Dwarf_Harmless_s *dhp = &dbg->de_harmless_errors;
130 unsigned next = 0;
131 unsigned cur = dhp->dh_next_to_use;
132 char *msgspace;
133 if (!dhp->dh_errors) {
134 dhp->dh_errs_count++;
135 return;
136 }
137 msgspace = dhp->dh_errors[cur];
138 safe_strncpy(msgspace, newerror,DW_HARMLESS_ERROR_MSG_STRING_SIZE);
139 next = (cur+1) % dhp->dh_maxcount;
140 dhp->dh_errs_count++;
141 dhp->dh_next_to_use = next;
142 if (dhp->dh_next_to_use == dhp->dh_first) {
143 /* Array is full set full invariant. */
144 dhp->dh_first = (dhp->dh_first+1) % dhp->dh_maxcount;
145 }
146 }
147
148 /* The size of the circular list of strings may be set
149 and reset as desired. Returns the previous size of
150 the list. If the list is shortened excess error entries
151 are simply dropped.
152 If the reallocation fails the list size is left unchanged.
153 Do not make this a long list!
154
155 Remember the maxcount we record is 1 > the user count,
156 so we adjust it so it looks like the user count.
157 */
dwarf_set_harmless_error_list_size(Dwarf_Debug dbg,unsigned maxcount)158 unsigned dwarf_set_harmless_error_list_size(Dwarf_Debug dbg,
159 unsigned maxcount )
160 {
161 struct Dwarf_Harmless_s *dhp = &dbg->de_harmless_errors;
162 unsigned prevcount = dhp->dh_maxcount;
163 if (maxcount != 0) {
164 ++maxcount;
165 if (maxcount != dhp->dh_maxcount) {
166 /* Assign transfers 'ownership' of the malloc areas
167 to oldarray. */
168 struct Dwarf_Harmless_s oldarray = *dhp;
169 /* Do not double increment the max, the init() func
170 increments it too. */
171 dwarf_harmless_init(dhp,maxcount-1);
172 if (oldarray.dh_next_to_use != oldarray.dh_first) {
173 unsigned i = 0;
174 for (i = oldarray.dh_first; i != oldarray.dh_next_to_use;
175 i = (i+1)%oldarray.dh_maxcount) {
176 dwarf_insert_harmless_error(dbg,oldarray.dh_errors[i]);
177 }
178 if (oldarray.dh_errs_count > dhp->dh_errs_count) {
179 dhp->dh_errs_count = oldarray.dh_errs_count;
180 }
181 }
182 dwarf_harmless_cleanout(&oldarray);
183 }
184 }
185 return prevcount-1;
186 }
187
188 /* Only callable from within libdwarf (as a practical matter)
189 */
190 void
dwarf_harmless_init(struct Dwarf_Harmless_s * dhp,unsigned size)191 dwarf_harmless_init(struct Dwarf_Harmless_s *dhp,unsigned size)
192 {
193 unsigned i = 0;
194 memset(dhp,0,sizeof(*dhp));
195 dhp->dh_maxcount = size +1;
196 dhp->dh_errors = (char **)malloc(sizeof( char *) *dhp->dh_maxcount);
197 if (!dhp->dh_errors) {
198 dhp->dh_maxcount = 0;
199 return;
200 }
201
202 for (i = 0; i < dhp->dh_maxcount; ++i) {
203 char *newstr =
204 (char *)malloc(DW_HARMLESS_ERROR_MSG_STRING_SIZE);
205 dhp->dh_errors[i] = newstr;
206 if (!newstr) {
207 dhp->dh_maxcount = 0;
208 /* Let it leak, the leak is a constrained amount. */
209 dhp->dh_errors = 0;
210 return;
211 }
212 /* We make the string content well-defined by an initial
213 NUL byte, but this is not really necessary. */
214 newstr[0] = 0;
215 }
216 }
217
218 void
dwarf_harmless_cleanout(struct Dwarf_Harmless_s * dhp)219 dwarf_harmless_cleanout(struct Dwarf_Harmless_s *dhp)
220 {
221 unsigned i = 0;
222 if (!dhp->dh_errors) {
223 return;
224 }
225 for (i = 0; i < dhp->dh_maxcount; ++i) {
226 free(dhp->dh_errors[i]);
227 dhp->dh_errors[i] = 0;
228 }
229 free(dhp->dh_errors);
230 dhp->dh_errors = 0;
231 dhp->dh_maxcount = 0;
232 }
233