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