Coverage Report

Created: 2017-10-25 09:10

/root/src/xen/xen/common/symbols.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * symbols.c: in-kernel printing of symbolic oopses and stack traces.
3
 *
4
 * Copyright 2002 Rusty Russell <rusty@rustcorp.com.au> IBM Corporation
5
 *
6
 * ChangeLog:
7
 *
8
 * (25/Aug/2004) Paulo Marques <pmarques@grupopie.com>
9
 *      Changed the compression method from stem compression to "table lookup"
10
 *      compression (see tools/symbols.c for a more complete description)
11
 */
12
13
#include <xen/symbols.h>
14
#include <xen/kernel.h>
15
#include <xen/init.h>
16
#include <xen/lib.h>
17
#include <xen/string.h>
18
#include <xen/spinlock.h>
19
#include <xen/virtual_region.h>
20
#include <public/platform.h>
21
#include <xen/guest_access.h>
22
23
#ifdef SYMBOLS_ORIGIN
24
extern const unsigned int symbols_offsets[];
25
0
#define symbols_address(n) (SYMBOLS_ORIGIN + symbols_offsets[n])
26
#else
27
extern const unsigned long symbols_addresses[];
28
#define symbols_address(n) symbols_addresses[n]
29
#endif
30
extern const unsigned int symbols_num_syms;
31
extern const u8 symbols_names[];
32
33
extern const struct symbol_offset symbols_sorted_offsets[];
34
35
extern const u8 symbols_token_table[];
36
extern const u16 symbols_token_index[];
37
38
extern const unsigned int symbols_markers[];
39
40
/* expand a compressed symbol data into the resulting uncompressed string,
41
   given the offset to where the symbol is in the compressed stream */
42
static unsigned int symbols_expand_symbol(unsigned int off, char *result)
43
0
{
44
0
    int len, skipped_first = 0;
45
0
    const u8 *tptr, *data;
46
0
47
0
    /* get the compressed symbol length from the first symbol byte */
48
0
    data = &symbols_names[off];
49
0
    len = *data;
50
0
    data++;
51
0
52
0
    /* update the offset to return the offset for the next symbol on
53
0
     * the compressed stream */
54
0
    off += len + 1;
55
0
56
0
    /* for every byte on the compressed symbol data, copy the table
57
0
       entry for that byte */
58
0
    while(len) {
59
0
        tptr = &symbols_token_table[ symbols_token_index[*data] ];
60
0
        data++;
61
0
        len--;
62
0
63
0
        while (*tptr) {
64
0
            if(skipped_first) {
65
0
                *result = *tptr;
66
0
                result++;
67
0
            } else
68
0
                skipped_first = 1;
69
0
            tptr++;
70
0
        }
71
0
    }
72
0
73
0
    *result = '\0';
74
0
75
0
    /* return to offset to the next symbol */
76
0
    return off;
77
0
}
78
79
/* find the offset on the compressed stream given and index in the
80
 * symbols array */
81
static unsigned int get_symbol_offset(unsigned long pos)
82
0
{
83
0
    const u8 *name;
84
0
    int i;
85
0
86
0
    /* use the closest marker we have. We have markers every 256 positions,
87
0
     * so that should be close enough */
88
0
    name = &symbols_names[ symbols_markers[pos>>8] ];
89
0
90
0
    /* sequentially scan all the symbols up to the point we're searching for.
91
0
     * Every symbol is stored in a [<len>][<len> bytes of data] format, so we
92
0
     * just need to add the len to the current pointer for every symbol we
93
0
     * wish to skip */
94
0
    for(i = 0; i < (pos&0xFF); i++)
95
0
        name = name + (*name) + 1;
96
0
97
0
    return name - symbols_names;
98
0
}
99
100
bool_t is_active_kernel_text(unsigned long addr)
101
2
{
102
2
    return !!find_text_region(addr);
103
2
}
104
105
const char *symbols_lookup(unsigned long addr,
106
                           unsigned long *symbolsize,
107
                           unsigned long *offset,
108
                           char *namebuf)
109
3
{
110
3
    unsigned long i, low, high, mid;
111
3
    unsigned long symbol_end = 0;
112
3
    const struct virtual_region *region;
113
3
114
3
    namebuf[KSYM_NAME_LEN] = 0;
115
3
    namebuf[0] = 0;
116
3
117
3
    region = find_text_region(addr);
118
3
    if (!region)
119
3
        return NULL;
120
3
121
0
    if (region->symbols_lookup)
122
0
        return region->symbols_lookup(addr, symbolsize, offset, namebuf);
123
0
124
0
        /* do a binary search on the sorted symbols_addresses array */
125
0
    low = 0;
126
0
    high = symbols_num_syms;
127
0
128
0
    while (high-low > 1) {
129
0
        mid = (low + high) / 2;
130
0
        if (symbols_address(mid) <= addr) low = mid;
131
0
        else high = mid;
132
0
    }
133
0
134
0
    /* search for the first aliased symbol. Aliased symbols are
135
0
           symbols with the same address */
136
0
    while (low && symbols_address(low - 1) == symbols_address(low))
137
0
        --low;
138
0
139
0
        /* Grab name */
140
0
    symbols_expand_symbol(get_symbol_offset(low), namebuf);
141
0
142
0
    /* Search for next non-aliased symbol */
143
0
    for (i = low + 1; i < symbols_num_syms; i++) {
144
0
        if (symbols_address(i) > symbols_address(low)) {
145
0
            symbol_end = symbols_address(i);
146
0
            break;
147
0
        }
148
0
    }
149
0
150
0
    /* if we found no next symbol, we use the end of the section */
151
0
    if (!symbol_end)
152
0
        symbol_end = is_kernel_inittext(addr) ?
153
0
            (unsigned long)_einittext : (unsigned long)_etext;
154
0
155
0
    *symbolsize = symbol_end - symbols_address(low);
156
0
    *offset = addr - symbols_address(low);
157
0
    return namebuf;
158
0
}
159
160
/*
161
 * Get symbol type information. This is encoded as a single char at the
162
 * beginning of the symbol name.
163
 */
164
static char symbols_get_symbol_type(unsigned int off)
165
0
{
166
0
    /*
167
0
     * Get just the first code, look it up in the token table,
168
0
     * and return the first char from this token.
169
0
     */
170
0
    return symbols_token_table[symbols_token_index[symbols_names[off + 1]]];
171
0
}
172
173
int xensyms_read(uint32_t *symnum, char *type,
174
                 unsigned long *address, char *name)
175
0
{
176
0
    /*
177
0
     * Symbols are most likely accessed sequentially so we remember position
178
0
     * from previous read. This can help us avoid the extra call to
179
0
     * get_symbol_offset().
180
0
     */
181
0
    static uint64_t next_symbol, next_offset;
182
0
    static DEFINE_SPINLOCK(symbols_mutex);
183
0
184
0
    if ( *symnum > symbols_num_syms )
185
0
        return -ERANGE;
186
0
    if ( *symnum == symbols_num_syms )
187
0
    {
188
0
        /* No more symbols */
189
0
        name[0] = '\0';
190
0
        return 0;
191
0
    }
192
0
193
0
    spin_lock(&symbols_mutex);
194
0
195
0
    if ( *symnum == 0 )
196
0
        next_offset = next_symbol = 0;
197
0
    if ( next_symbol != *symnum )
198
0
        /* Non-sequential access */
199
0
        next_offset = get_symbol_offset(*symnum);
200
0
201
0
    *type = symbols_get_symbol_type(next_offset);
202
0
    next_offset = symbols_expand_symbol(next_offset, name);
203
0
    *address = symbols_address(*symnum);
204
0
205
0
    next_symbol = ++*symnum;
206
0
207
0
    spin_unlock(&symbols_mutex);
208
0
209
0
    return 0;
210
0
}
211
212
unsigned long symbols_lookup_by_name(const char *symname)
213
0
{
214
0
    char name[KSYM_NAME_LEN + 1];
215
0
#ifdef CONFIG_FAST_SYMBOL_LOOKUP
216
    unsigned long low, high;
217
#else
218
0
    uint32_t symnum = 0;
219
0
    char type;
220
0
    unsigned long addr;
221
0
    int rc;
222
0
#endif
223
0
224
0
    if ( *symname == '\0' )
225
0
        return 0;
226
0
227
0
#ifdef CONFIG_FAST_SYMBOL_LOOKUP
228
    low = 0;
229
    high = symbols_num_syms;
230
    while ( low < high )
231
    {
232
        unsigned long mid = low + ((high - low) / 2);
233
        const struct symbol_offset *s;
234
        int rc;
235
236
        s = &symbols_sorted_offsets[mid];
237
        (void)symbols_expand_symbol(s->stream, name);
238
        /* Format is: [filename]#<symbol>. symbols_expand_symbol eats type.*/
239
        rc = strcmp(symname, name);
240
        if ( rc < 0 )
241
            high = mid;
242
        else if ( rc > 0 )
243
            low = mid + 1;
244
        else
245
            return symbols_address(s->addr);
246
    }
247
#else
248
0
    do {
249
0
        rc = xensyms_read(&symnum, &type, &addr, name);
250
0
        if ( rc )
251
0
           break;
252
0
253
0
        if ( !strcmp(name, symname) )
254
0
            return addr;
255
0
256
0
    } while ( name[0] != '\0' );
257
0
258
0
#endif
259
0
    return 0;
260
0
}
261
262
/*
263
 * Local variables:
264
 * mode: C
265
 * c-file-style: "BSD"
266
 * c-basic-offset: 4
267
 * tab-width: 4
268
 * indent-tabs-mode: nil
269
 * End:
270
 */