source: trunk/packages/xen-3.1/xen-3.1/xen/common/symbols.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 17 years ago

Add xen and xen-common

File size: 4.6 KB
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/config.h>
14#include <xen/symbols.h>
15#include <xen/kernel.h>
16#include <xen/init.h>
17#include <xen/lib.h>
18#include <xen/string.h>
19#include <xen/spinlock.h>
20
21extern unsigned long symbols_addresses[];
22extern unsigned long symbols_num_syms;
23extern u8 symbols_names[];
24
25extern u8 symbols_token_table[];
26extern u16 symbols_token_index[];
27
28extern unsigned long symbols_markers[];
29
30/* expand a compressed symbol data into the resulting uncompressed string,
31   given the offset to where the symbol is in the compressed stream */
32static unsigned int symbols_expand_symbol(unsigned int off, char *result)
33{
34    int len, skipped_first = 0;
35    u8 *tptr, *data;
36
37    /* get the compressed symbol length from the first symbol byte */
38    data = &symbols_names[off];
39    len = *data;
40    data++;
41
42    /* update the offset to return the offset for the next symbol on
43     * the compressed stream */
44    off += len + 1;
45
46    /* for every byte on the compressed symbol data, copy the table
47       entry for that byte */
48    while(len) {
49        tptr = &symbols_token_table[ symbols_token_index[*data] ];
50        data++;
51        len--;
52
53        while (*tptr) {
54            if(skipped_first) {
55                *result = *tptr;
56                result++;
57            } else
58                skipped_first = 1;
59            tptr++;
60        }
61    }
62
63    *result = '\0';
64
65    /* return to offset to the next symbol */
66    return off;
67}
68
69/* find the offset on the compressed stream given and index in the
70 * symbols array */
71static unsigned int get_symbol_offset(unsigned long pos)
72{
73    u8 *name;
74    int i;
75
76    /* use the closest marker we have. We have markers every 256 positions,
77     * so that should be close enough */
78    name = &symbols_names[ symbols_markers[pos>>8] ];
79
80    /* sequentially scan all the symbols up to the point we're searching for.
81     * Every symbol is stored in a [<len>][<len> bytes of data] format, so we
82     * just need to add the len to the current pointer for every symbol we
83     * wish to skip */
84    for(i = 0; i < (pos&0xFF); i++)
85        name = name + (*name) + 1;
86
87    return name - symbols_names;
88}
89
90const char *symbols_lookup(unsigned long addr,
91                           unsigned long *symbolsize,
92                           unsigned long *offset,
93                           char *namebuf)
94{
95    unsigned long i, low, high, mid;
96    unsigned long symbol_end = 0;
97
98    namebuf[KSYM_NAME_LEN] = 0;
99    namebuf[0] = 0;
100
101    if (!is_kernel_text(addr) && !is_kernel_inittext(addr))
102        return NULL;
103
104        /* do a binary search on the sorted symbols_addresses array */
105    low = 0;
106    high = symbols_num_syms;
107
108    while (high-low > 1) {
109        mid = (low + high) / 2;
110        if (symbols_addresses[mid] <= addr) low = mid;
111        else high = mid;
112    }
113
114    /* search for the first aliased symbol. Aliased symbols are
115           symbols with the same address */
116    while (low && symbols_addresses[low - 1] == symbols_addresses[low])
117        --low;
118
119        /* Grab name */
120    symbols_expand_symbol(get_symbol_offset(low), namebuf);
121
122    /* Search for next non-aliased symbol */
123    for (i = low + 1; i < symbols_num_syms; i++) {
124        if (symbols_addresses[i] > symbols_addresses[low]) {
125            symbol_end = symbols_addresses[i];
126            break;
127        }
128    }
129
130    /* if we found no next symbol, we use the end of the section */
131    if (!symbol_end)
132        symbol_end = is_kernel_inittext(addr) ?
133            (unsigned long)_einittext : (unsigned long)_etext;
134
135    *symbolsize = symbol_end - symbols_addresses[low];
136    *offset = addr - symbols_addresses[low];
137    return namebuf;
138}
139
140/* Replace "%s" in format with address, or returns -errno. */
141void __print_symbol(const char *fmt, unsigned long address)
142{
143    const char *name;
144    unsigned long offset, size, flags;
145
146    static DEFINE_SPINLOCK(lock);
147    static char namebuf[KSYM_NAME_LEN+1];
148#define BUFFER_SIZE sizeof("%s+%#lx/%#lx [%s]") + KSYM_NAME_LEN + \
149                        2*(BITS_PER_LONG*3/10) + 1
150    static char buffer[BUFFER_SIZE];
151
152    spin_lock_irqsave(&lock, flags);
153
154    name = symbols_lookup(address, &size, &offset, namebuf);
155
156    if (!name)
157        snprintf(buffer, BUFFER_SIZE, "???");
158    else
159        snprintf(buffer, BUFFER_SIZE, "%s+%#lx/%#lx", name, offset, size);
160
161    printk(fmt, buffer);
162
163    spin_unlock_irqrestore(&lock, flags);
164}
Note: See TracBrowser for help on using the repository browser.