summaryrefslogtreecommitdiff
path: root/libdwarf/dwarf_harmless.c
blob: 0329bc9fe0861b3bcff3e98e4ef5bf14b774a516 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
/*

  Copyright (C) 2010-2011 David Anderson. All Rights Reserved.

  This program is free software; you can redistribute it and/or modify it
  under the terms of version 2.1 of the GNU Lesser General Public License 
  as published by the Free Software Foundation.

  This program is distributed in the hope that it would be useful, but
  WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  

  Further, this software is distributed without any warranty that it is
  free of the rightful claim of any third person regarding infringement 
  or the like.  Any license provided herein, whether implied or 
  otherwise, applies only to this software file.  Patent licenses, if
  any, provided herein do not apply to combinations of this program with 
  other software, or any other product whatsoever.  

  You should have received a copy of the GNU Lesser General Public 
  License along with this program; if not, write the Free Software 
  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
  USA.

*/

/*  This  implements _dwarf_insert_harmless_error
    and related helper functions for recording
    compiler errors that need not make the input
    unusable.
 
    Applications can use dwarf_get_harmless_error_list to
    find (and possibly print) a warning about such errors.

    The initial error reported here is 
    DW_DLE_DEBUG_FRAME_LENGTH_NOT_MULTIPLE which was a
    bug in a specific compiler.

    It is a fixed length circular list to constrain
    the space used for errors.

    The assumption is that these errors are exceedingly
    rare, and indicate a broken compiler (the one that
    produced the object getting the error(s)).

    dh_maxcount is recorded internally as 1 greater than
    requested.  Hiding the fact we always leave one
    slot unused (at least).   So a user request for
    N slots really gives the user N usable slots.  */



#include "config.h"
#include "dwarf_incl.h"
#include <stdio.h>
#include <stdlib.h>
#include "dwarf_frame.h"
#include "dwarf_harmless.h"


/*  The pointers returned here through errmsg_ptrs_array
    become invalidated by any call to libdwarf. Any call.
*/
int dwarf_get_harmless_error_list(Dwarf_Debug dbg,
    unsigned  count,
    const char ** errmsg_ptrs_array,
    unsigned * errs_count)
{
    struct Dwarf_Harmless_s *dhp = &dbg->de_harmless_errors;
    if(!dhp->dh_errors) {
        dhp->dh_errs_count = 0;
        return DW_DLV_NO_ENTRY;
    }
    if(dhp->dh_errs_count == 0) {
        return DW_DLV_NO_ENTRY;
    }
    if(errs_count) {
        *errs_count = dhp->dh_errs_count;
    }
    if(count) {
        /* NULL terminate the array of pointers */
        --count;
        errmsg_ptrs_array[count] = 0;

        if(dhp->dh_next_to_use != dhp->dh_first) {
            unsigned i = 0;
            unsigned cur = dhp->dh_first;
            for(i = 0;  cur != dhp->dh_next_to_use; ++i) {
                if(i >= count ) {
                    /* All output spaces are used. */
                    break;
                }
                errmsg_ptrs_array[i] = dhp->dh_errors[cur];
                cur = (cur +1) % dhp->dh_maxcount;
            }
            errmsg_ptrs_array[i] = 0;
        }
    }
    dhp->dh_next_to_use = 0;
    dhp->dh_first = 0;
    dhp->dh_errs_count = 0;
    return DW_DLV_OK;
}

/*  strncpy does not null-terminate, this does it. */
static void
safe_strncpy(char *targ, char *src, unsigned spaceavail)
{
    unsigned goodcount = spaceavail-1;
    if(spaceavail < 1) {
        return; /* impossible */
    }
    strncpy(targ,src,goodcount);
    targ[goodcount] = 0;
}

/*  Insertion made public is only for testing the harmless error code, 
    it is not necessarily useful for libdwarf client code aside
    from code testing libdwarf. */
void dwarf_insert_harmless_error(Dwarf_Debug dbg,
    char *newerror)
{
    struct Dwarf_Harmless_s *dhp = &dbg->de_harmless_errors;
    unsigned next = 0;
    unsigned cur = dhp->dh_next_to_use;
    char *msgspace;
    if(!dhp->dh_errors) {
        dhp->dh_errs_count++;
        return;
    }
    msgspace = dhp->dh_errors[cur];
    safe_strncpy(msgspace, newerror,DW_HARMLESS_ERROR_MSG_STRING_SIZE);
    next = (cur+1) % dhp->dh_maxcount;
    dhp->dh_errs_count++;
    dhp->dh_next_to_use = next;
    if (dhp->dh_next_to_use ==  dhp->dh_first) {
        /* Array is full set full invariant. */
        dhp->dh_first = (dhp->dh_first+1) % dhp->dh_maxcount;
    }
}

/*  The size of the circular list of strings may be set
    and reset as desired. Returns the previous size of
    the list. If the list is shortened excess error entries
    are simply dropped. 
    If the reallocation fails the list size is left unchanged.
    Do not make this a long list!

    Remember the maxcount we record is 1 > the user count,
    so we adjust it so it looks like the user count.
*/
unsigned dwarf_set_harmless_error_list_size(Dwarf_Debug dbg,
    unsigned maxcount )
{
    struct Dwarf_Harmless_s *dhp = &dbg->de_harmless_errors;
    unsigned prevcount = dhp->dh_maxcount;
    if(maxcount != 0) {
        ++maxcount;
        if(maxcount != dhp->dh_maxcount) {
            /*  Assign transfers 'ownership' of the malloc areas
                to oldarray. */
            struct Dwarf_Harmless_s oldarray = *dhp;
            /*  Do not double increment the max, the init() func
                increments it too. */
            dwarf_harmless_init(dhp,maxcount-1);
            if(oldarray.dh_next_to_use != oldarray.dh_first) {
                unsigned i = 0;
                for(i = oldarray.dh_first; i != oldarray.dh_next_to_use; 
                    i = (i+1)%oldarray.dh_maxcount) {
                    dwarf_insert_harmless_error(dbg,oldarray.dh_errors[i]);
                }
                if( oldarray.dh_errs_count > dhp->dh_errs_count) {
                    dhp->dh_errs_count = oldarray.dh_errs_count;
                }
            }
            dwarf_harmless_cleanout(&oldarray);
        }
    }
    return prevcount-1;
}

/*  Only callable from within libdwarf (as a practical matter)
*/
void 
dwarf_harmless_init(struct Dwarf_Harmless_s *dhp,unsigned size)
{
    unsigned i = 0;
    memset(dhp,0,sizeof(*dhp));
    dhp->dh_maxcount = size +1;
    dhp->dh_errors = (char **)malloc(sizeof( char *) *dhp->dh_maxcount);
    if (!dhp->dh_errors) {
        dhp->dh_maxcount = 0;
        return;
    }

    for(i = 0; i < dhp->dh_maxcount; ++i) {
        char *newstr =
            (char *)malloc(DW_HARMLESS_ERROR_MSG_STRING_SIZE);
        dhp->dh_errors[i] = newstr;
        if(!newstr) {
            dhp->dh_maxcount = 0;
            /* Let it leak, the leak is a constrained amount. */
            dhp->dh_errors = 0;
            return;
        }
        /*  We make the string content well-defined by an initial
            NUL byte, but this is not really necessary. */
        newstr[0] = 0;
    }
}

void 
dwarf_harmless_cleanout(struct Dwarf_Harmless_s *dhp)
{
    unsigned i = 0;
    if(!dhp->dh_errors) {
        return;
    }
    for(i = 0; i < dhp->dh_maxcount; ++i) {
        free(dhp->dh_errors[i]);
    } 
    free(dhp->dh_errors); 
    dhp->dh_errors = 0;     
    dhp->dh_maxcount = 0;     
}