]> sourceware.org Git - systemtap.git/blob - runtime/sym.c
2007-01-31 Martin Hunt <hunt@redhat.com>
[systemtap.git] / runtime / sym.c
1 /* -*- linux-c -*-
2 * Symbolic Lookup Functions
3 * Copyright (C) 2005, 2006, 2007 Red Hat Inc.
4 * Copyright (C) 2006 Intel Corporation.
5 *
6 * This file is part of systemtap, and is free software. You can
7 * redistribute it and/or modify it under the terms of the GNU General
8 * Public License (GPL); either version 2, or (at your option) any
9 * later version.
10 */
11
12 #ifndef _SYM_C_
13 #define _SYM_C_
14
15 #include "string.c"
16
17 /** @file sym.c
18 * @addtogroup sym Symbolic Functions
19 * Symbolic Lookup Functions
20 * @{
21 */
22
23 static unsigned long _stp_module_relocate (const char *module, const char *section, unsigned long offset) {
24 static struct _stp_module *last = NULL;
25 static struct _stp_symbol *last_sec;
26 unsigned long flags;
27 int i,j;
28
29 STP_LOCK_MODULES;
30 if (! module || _stp_num_modules == 0) {
31 STP_UNLOCK_MODULES;
32 return offset;
33 }
34
35 if (last) {
36 if (!strcmp (module, last->name) && !strcmp (section, last_sec->symbol)) {
37 STP_UNLOCK_MODULES;
38 return offset + last_sec->addr;
39 }
40 }
41
42 /* need to scan all modules */
43 for (i = 1; i < _stp_num_modules; i++) { /* XXX: why start at i=1? */
44 last = _stp_modules[i];
45 if (strcmp(module, last->name))
46 continue;
47 for (j = 0; j < last->num_sections; j++) {
48 last_sec = &last->sections[j];
49 if (!strcmp (section, last_sec->symbol)) {
50 STP_UNLOCK_MODULES;
51 return offset + last_sec->addr;
52 }
53 }
54 }
55 STP_UNLOCK_MODULES;
56 last = NULL;
57 return 0;
58 }
59
60 /* Lookup the kernel address for this symbol. Returns 0 if not found. */
61 static unsigned long _stp_kallsyms_lookup_name(const char *name)
62 {
63 struct _stp_symbol *s = _stp_modules[0]->symbols;
64 unsigned num = _stp_modules[0]->num_symbols;
65
66 while (num--) {
67 if (strcmp(name, s->symbol) == 0)
68 return s->addr;
69 s++;
70 }
71 return 0;
72 }
73
74 static const char * _stp_kallsyms_lookup (
75 unsigned long addr,
76 unsigned long *symbolsize,
77 unsigned long *offset,
78 char **modname,
79 char *namebuf)
80 {
81 struct _stp_module *m;
82 struct _stp_symbol *s;
83 unsigned long flags;
84 unsigned end, begin = 0;
85
86 if (STP_TRYLOCK_MODULES)
87 return NULL;
88
89 end = _stp_num_modules;
90
91 if (_stp_num_modules >= 2 && addr > _stp_modules_by_addr[1]->text) {
92 /* binary search on index [begin,end) */
93 do {
94 unsigned mid = (begin + end) / 2;
95 if (addr < _stp_modules_by_addr[mid]->text)
96 end = mid;
97 else
98 begin = mid;
99 } while (begin + 1 < end);
100 /* result index in $begin, guaranteed between [0,_stp_num_modules) */
101 }
102 m = _stp_modules_by_addr[begin];
103 begin = 0;
104 end = m->num_symbols;
105
106 /* binary search for symbols within the module */
107 do {
108 unsigned mid = (begin + end) / 2;
109 if (addr < m->symbols[mid].addr)
110 end = mid;
111 else
112 begin = mid;
113 } while (begin + 1 < end);
114 /* result index in $begin */
115
116 s = &m->symbols[begin];
117 if (addr < s->addr) {
118 STP_UNLOCK_MODULES;
119 return NULL;
120 } else {
121 if (offset) *offset = addr - s->addr;
122 if (modname) *modname = m->name;
123 if (symbolsize) {
124 if ((begin + 1) < m->num_symbols)
125 *symbolsize = m->symbols[begin+1].addr - s->addr;
126 else
127 *symbolsize = 0;
128 // NB: This is only a heuristic. Sometimes there are large
129 // gaps between text areas of modules.
130 }
131 if (namebuf) {
132 strlcpy (namebuf, s->symbol, KSYM_NAME_LEN+1);
133 STP_UNLOCK_MODULES;
134 return namebuf;
135 }
136 else {
137 STP_UNLOCK_MODULES;
138 return s->symbol;
139 }
140 }
141 STP_UNLOCK_MODULES;
142 return NULL;
143 }
144
145 /** Print an address symbolically.
146 * @param address The address to lookup.
147 * @note Symbolic lookups should not normally be done within
148 * a probe because it is too time-consuming. Use at module exit time.
149 */
150
151 void _stp_symbol_print (unsigned long address)
152 {
153 char *modname;
154 const char *name;
155 unsigned long offset, size;
156 char namebuf[KSYM_NAME_LEN+1];
157
158 name = _stp_kallsyms_lookup(address, &size, &offset, &modname, namebuf);
159
160 _stp_printf ("%p", (void *)address);
161
162 if (name) {
163 if (modname)
164 _stp_printf (" : %s+%#lx/%#lx [%s]", name, offset, size, modname);
165 else
166 _stp_printf (" : %s+%#lx/%#lx", name, offset, size);
167 }
168 }
169
170 void _stp_symbol_snprint (char *str, size_t len, unsigned long address)
171 {
172 char *modname;
173 const char *name;
174 unsigned long offset, size;
175 char namebuf[KSYM_NAME_LEN+1];
176
177 if (len > KSYM_NAME_LEN) {
178 name = _stp_kallsyms_lookup(address, &size, &offset, &modname, str);
179 if (!name)
180 snprintf(str, len, "%p", (void *)address);
181 } else {
182 name = _stp_kallsyms_lookup(address, &size, &offset, &modname, namebuf);
183 if (name)
184 strlcpy(str, namebuf, len);
185 else
186 snprintf(str, len, "%p", (void *)address);
187 }
188 }
189
190 /** @} */
191 #endif /* _SYM_C_ */
This page took 0.043139 seconds and 5 git commands to generate.