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*/
66int 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. */
108static void
109safe_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. */
122void 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*/
154unsigned 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
184void
185dwarf_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
212void
213dwarf_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