13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25 #include "asm/assembler.hpp"
26 #include "memory/allocation.hpp"
27 #include "memory/allocation.inline.hpp"
28 #include "runtime/os.hpp"
29 #include "loadlib_aix.hpp"
30 #include "porting_aix.hpp"
31 #include "utilities/debug.hpp"
32
33 #include <demangle.h>
34 #include <sys/debug.h>
35
36 //////////////////////////////////
37 // Provide implementation for dladdr based on LoadedLibraries pool and
38 // traceback table scan (see getFuncName).
39
40 // Search traceback table in stack,
41 // return procedure name from trace back table.
42 #define MAX_FUNC_SEARCH_LEN 0x10000
43 // Any PC below this value is considered toast.
44 #define MINIMUM_VALUE_FOR_PC ((unsigned int*)0x1024)
45
46 #define PTRDIFF_BYTES(p1,p2) (((ptrdiff_t)p1) - ((ptrdiff_t)p2))
47
48 // Align a pointer without having to cast.
49 inline char* align_ptr_up(char* ptr, intptr_t alignment) {
50 return (char*) align_size_up((intptr_t)ptr, alignment);
51 }
52
53 // Trace if verbose to tty.
54 // I use these now instead of the Xtrace system because the latter is
55 // not available at init time, hence worthless. Until we fix this, all
56 // tracing here is done with -XX:+Verbose.
57 #define trcVerbose(fmt, ...) { \
58 if (Verbose) { \
59 fprintf(stderr, fmt, ##__VA_ARGS__); \
60 fputc('\n', stderr); fflush(stderr); \
61 } \
62 }
63 #define ERRBYE(s) { trcVerbose(s); return -1; }
64
65 // Unfortunately, the interface of dladdr makes the implementator
66 // responsible for maintaining memory for function name/library
67 // name. I guess this is because most OS's keep those values as part
68 // of the mapped executable image ready to use. On AIX, this doesn't
69 // work, so I have to keep the returned strings. For now, I do this in
70 // a primitive string map. Should this turn out to be a performance
71 // problem, a better hashmap has to be used.
72 class fixed_strings {
122
123 // initialize output parameters
124 if (p_name && namelen > 0) {
125 *p_name = '\0';
126 }
127 if (p_errmsg && errmsglen > 0) {
128 *p_errmsg = '\0';
129 }
130 if (p_displacement) {
131 *p_displacement = -1;
132 }
133 if (p_tb) {
134 *p_tb = NULL;
135 }
136
137 // weed out obvious bogus states
138 if (pc < MINIMUM_VALUE_FOR_PC) {
139 ERRBYE("invalid program counter");
140 }
141
142 codeptr_t pc2 = pc;
143
144 // make sure the pointer is word aligned.
145 pc2 = (codeptr_t) align_ptr_up((char*)pc2, 4);
146
147 // Find start of traceback table.
148 // (starts after code, is marked by word-aligned (32bit) zeros)
149 while ((*pc2 != NULL) && (searchcount++ < MAX_FUNC_SEARCH_LEN)) {
150 pc2++;
151 }
152 if (*pc2 != 0) {
153 ERRBYE("could not find traceback table within 5000 bytes of program counter");
154 }
155 //
156 // Set up addressability to the traceback table
157 //
158 tb = (struct tbtable*) (pc2 + 1);
159
160 // Is this really a traceback table? No way to be sure but
161 // some indicators we can check.
162 if (tb->tb.lang >= 0xf && tb->tb.lang <= 0xfb) {
163 // Language specifiers, go from 0 (C) to 14 (Objective C).
164 // According to spec, 0xf-0xfa reserved, 0xfb-0xff reserved for ibm.
165 ERRBYE("not a traceback table");
166 }
167
168 // Existence of fields in the tbtable extension are contingent upon
169 // specific fields in the base table. Check for their existence so
170 // that we can address the function name if it exists.
171 pc2 = (codeptr_t) tb +
172 sizeof(struct tbtable_short)/sizeof(int);
173 if (tb->tb.fixedparms != 0 || tb->tb.floatparms != 0)
174 pc2++;
175
176 if (tb->tb.has_tboff == TRUE) {
177
178 // I want to know the displacement
179 const unsigned int tb_offset = *pc2;
180 codeptr_t start_of_procedure =
181 (codeptr_t)(((char*)tb) - 4 - tb_offset); // (-4 to omit leading 0000)
182
183 // Weed out the cases where we did find the wrong traceback table.
184 if (pc < start_of_procedure) {
185 ERRBYE("could not find (the real) traceback table within 5000 bytes of program counter");
186 }
187
188 // return the displacement
189 if (p_displacement) {
190 (*p_displacement) = (int) PTRDIFF_BYTES(pc, start_of_procedure);
191 }
192
193 pc2++;
194 } else {
195 // return -1 for displacement
196 if (p_displacement) {
197 (*p_displacement) = -1;
198 }
199 }
200
201 if (tb->tb.int_hndl == TRUE)
202 pc2++;
203
204 if (tb->tb.has_ctl == TRUE)
205 pc2 += (*pc2) + 1; // don't care
206
207 //
208 // return function name if it exists.
209 //
210 if (p_name && namelen > 0) {
211 if (tb->tb.name_present) {
212 char buf[256];
213 const short l = MIN2<short>(*((short*)pc2), sizeof(buf) - 1);
214 memcpy(buf, (char*)pc2 + sizeof(short), l);
215 buf[l] = '\0';
216
217 p_name[0] = '\0';
218
219 // If it is a C++ name, try and demangle it using the Demangle interface (see demangle.h).
220 if (demangle) {
221 char* rest;
222 Name* const name = Demangle(buf, rest);
223 if (name) {
224 const char* const demangled_name = name->Text();
225 if (demangled_name) {
226 strncpy(p_name, demangled_name, namelen-1);
227 p_name[namelen-1] = '\0';
228 }
229 delete name;
230 }
231 }
232
233 // Fallback: if demangling did not work, just provide the unmangled name.
234 if (p_name[0] == '\0') {
235 strncpy(p_name, buf, namelen-1);
258 extern "C"
259 int dladdr(void* addr, Dl_info* info) {
260
261 if (!addr) {
262 return 0;
263 }
264
265 assert(info, "");
266
267 int rc = 0;
268
269 const char* const ZEROSTRING = "";
270
271 // Always return a string, even if a "" one. Linux dladdr manpage
272 // does not say anything about returning NULL
273 info->dli_fname = ZEROSTRING;
274 info->dli_sname = ZEROSTRING;
275 info->dli_saddr = NULL;
276
277 address p = (address) addr;
278 const LoadedLibraryModule* lib = NULL;
279
280 enum { noclue, code, data } type = noclue;
281
282 trcVerbose("dladdr(%p)...", p);
283
284 // Note: input address may be a function. I accept both a pointer to
285 // the entry of a function and a pointer to the function decriptor.
286 // (see ppc64 ABI)
287 lib = LoadedLibraries::find_for_text_address(p);
288 if (lib) {
289 type = code;
290 }
291
292 if (!lib) {
293 // Not a pointer into any text segment. Is it a function descriptor?
294 const FunctionDescriptor* const pfd = (const FunctionDescriptor*) p;
295 p = pfd->entry();
296 if (p) {
297 lib = LoadedLibraries::find_for_text_address(p);
298 if (lib) {
299 type = code;
300 }
301 }
302 }
303
304 if (!lib) {
305 // Neither direct code pointer nor function descriptor. A data ptr?
306 p = (address)addr;
307 lib = LoadedLibraries::find_for_data_address(p);
308 if (lib) {
309 type = data;
310 }
311 }
312
313 // If we did find the shared library this address belongs to (either
314 // code or data segment) resolve library path and, if possible, the
315 // symbol name.
316 if (lib) {
317 const char* const interned_libpath =
318 dladdr_fixed_strings.intern(lib->get_fullpath());
319 if (interned_libpath) {
320 info->dli_fname = interned_libpath;
321 }
322
323 if (type == code) {
324
325 // For code symbols resolve function name and displacement. Use
326 // displacement to calc start of function.
327 char funcname[256] = "";
328 int displacement = 0;
329
330 if (getFuncName((codeptr_t) p, funcname, sizeof(funcname), &displacement,
331 NULL, NULL, 0, true /* demangle */) == 0) {
332 if (funcname[0] != '\0') {
333 const char* const interned = dladdr_fixed_strings.intern(funcname);
334 info->dli_sname = interned;
335 trcVerbose("... function name: %s ...", interned);
336 }
337
338 // From the displacement calculate the start of the function.
339 if (displacement != -1) {
340 info->dli_saddr = p - displacement;
341 } else {
342 info->dli_saddr = p;
343 }
344 } else {
345
346 // No traceback table found. Just assume the pointer is it.
347 info->dli_saddr = p;
348
349 }
350
351 } else if (type == data) {
354 info->dli_saddr = p;
355
356 } else {
357 ShouldNotReachHere();
358 }
359
360 rc = 1; // success: return 1 [sic]
361
362 }
363
364 // sanity checks.
365 if (rc) {
366 assert(info->dli_fname, "");
367 assert(info->dli_sname, "");
368 assert(info->dli_saddr, "");
369 }
370
371 return rc; // error: return 0 [sic]
372
373 }
|
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25 #include "asm/assembler.hpp"
26 #include "memory/allocation.hpp"
27 #include "memory/allocation.inline.hpp"
28 #include "runtime/os.hpp"
29 #include "loadlib_aix.hpp"
30 #include "porting_aix.hpp"
31 #include "utilities/debug.hpp"
32
33 // For CritSect
34 #include "misc_aix.hpp"
35
36 #include <demangle.h>
37 #include <sys/debug.h>
38
39 //////////////////////////////////
40 // Provide implementation for dladdr based on LoadedLibraries pool and
41 // traceback table scan (see getFuncName).
42
43 // Search traceback table in stack,
44 // return procedure name from trace back table.
45 #define MAX_FUNC_SEARCH_LEN 0x10000
46 // Any PC below this value is considered toast.
47 #define MINIMUM_VALUE_FOR_PC ((unsigned int*)0x1024)
48
49 #define PTRDIFF_BYTES(p1,p2) (((ptrdiff_t)p1) - ((ptrdiff_t)p2))
50
51 // Trace if verbose to tty.
52 // I use these now instead of the Xtrace system because the latter is
53 // not available at init time, hence worthless. Until we fix this, all
54 // tracing here is done with -XX:+Verbose.
55 #define trcVerbose(fmt, ...) { \
56 if (Verbose) { \
57 fprintf(stderr, fmt, ##__VA_ARGS__); \
58 fputc('\n', stderr); fflush(stderr); \
59 } \
60 }
61 #define ERRBYE(s) { trcVerbose(s); return -1; }
62
63 // Unfortunately, the interface of dladdr makes the implementator
64 // responsible for maintaining memory for function name/library
65 // name. I guess this is because most OS's keep those values as part
66 // of the mapped executable image ready to use. On AIX, this doesn't
67 // work, so I have to keep the returned strings. For now, I do this in
68 // a primitive string map. Should this turn out to be a performance
69 // problem, a better hashmap has to be used.
70 class fixed_strings {
120
121 // initialize output parameters
122 if (p_name && namelen > 0) {
123 *p_name = '\0';
124 }
125 if (p_errmsg && errmsglen > 0) {
126 *p_errmsg = '\0';
127 }
128 if (p_displacement) {
129 *p_displacement = -1;
130 }
131 if (p_tb) {
132 *p_tb = NULL;
133 }
134
135 // weed out obvious bogus states
136 if (pc < MINIMUM_VALUE_FOR_PC) {
137 ERRBYE("invalid program counter");
138 }
139
140 // We see random but frequent crashes in this function since some months mainly on shutdown
141 // (-XX:+DumpInfoAtExit). It appears the page we are reading is randomly disappearing while
142 // we read it (?).
143 // As the pc cannot be trusted to be anything sensible lets make all reads via SafeFetch. Also
144 // bail if this is not a text address right now.
145 if (!LoadedLibraries::find_for_text_address(pc, NULL)) {
146 ERRBYE("not a text address");
147 }
148
149 // .. (note that is_readable_pointer returns true if safefetch stubs are not there yet;
150 // in that case I try reading the traceback table unsafe - I rather risk secondary crashes in
151 // error files than not having a callstack)
152 #define CHECK_POINTER_READABLE(p) \
153 if (!MiscUtils::is_readable_pointer(p)) { \
154 ERRBYE("pc not readable"); \
155 }
156
157 codeptr_t pc2 = pc;
158
159 // make sure the pointer is word aligned.
160 pc2 = (codeptr_t) align_ptr_up((char*)pc2, 4);
161 CHECK_POINTER_READABLE(pc2)
162
163 // Find start of traceback table.
164 // (starts after code, is marked by word-aligned (32bit) zeros)
165 while ((*pc2 != NULL) && (searchcount++ < MAX_FUNC_SEARCH_LEN)) {
166 CHECK_POINTER_READABLE(pc2)
167 pc2++;
168 }
169 if (*pc2 != 0) {
170 ERRBYE("no traceback table found");
171 }
172 //
173 // Set up addressability to the traceback table
174 //
175 tb = (struct tbtable*) (pc2 + 1);
176
177 // Is this really a traceback table? No way to be sure but
178 // some indicators we can check.
179 if (tb->tb.lang >= 0xf && tb->tb.lang <= 0xfb) {
180 // Language specifiers, go from 0 (C) to 14 (Objective C).
181 // According to spec, 0xf-0xfa reserved, 0xfb-0xff reserved for ibm.
182 ERRBYE("no traceback table found");
183 }
184
185 // Existence of fields in the tbtable extension are contingent upon
186 // specific fields in the base table. Check for their existence so
187 // that we can address the function name if it exists.
188 pc2 = (codeptr_t) tb +
189 sizeof(struct tbtable_short)/sizeof(int);
190 if (tb->tb.fixedparms != 0 || tb->tb.floatparms != 0)
191 pc2++;
192
193 CHECK_POINTER_READABLE(pc2)
194
195 if (tb->tb.has_tboff == TRUE) {
196
197 // I want to know the displacement
198 const unsigned int tb_offset = *pc2;
199 codeptr_t start_of_procedure =
200 (codeptr_t)(((char*)tb) - 4 - tb_offset); // (-4 to omit leading 0000)
201
202 // Weed out the cases where we did find the wrong traceback table.
203 if (pc < start_of_procedure) {
204 ERRBYE("no traceback table found");
205 }
206
207 // return the displacement
208 if (p_displacement) {
209 (*p_displacement) = (int) PTRDIFF_BYTES(pc, start_of_procedure);
210 }
211
212 pc2++;
213 } else {
214 // return -1 for displacement
215 if (p_displacement) {
216 (*p_displacement) = -1;
217 }
218 }
219
220 if (tb->tb.int_hndl == TRUE)
221 pc2++;
222
223 if (tb->tb.has_ctl == TRUE)
224 pc2 += (*pc2) + 1; // don't care
225
226 CHECK_POINTER_READABLE(pc2)
227
228 //
229 // return function name if it exists.
230 //
231 if (p_name && namelen > 0) {
232 if (tb->tb.name_present) {
233 // copy name from text because it may not be zero terminated.
234 // 256 is good enough for most cases; do not use large buffers here.
235 char buf[256];
236 const short l = MIN2<short>(*((short*)pc2), sizeof(buf) - 1);
237 // be very careful.
238 int i = 0; char* const p = (char*)pc2 + sizeof(short);
239 while (i < l && MiscUtils::is_readable_pointer(p + i)) {
240 buf[i] = p[i];
241 i++;
242 }
243 buf[i] = '\0';
244
245 p_name[0] = '\0';
246
247 // If it is a C++ name, try and demangle it using the Demangle interface (see demangle.h).
248 if (demangle) {
249 char* rest;
250 Name* const name = Demangle(buf, rest);
251 if (name) {
252 const char* const demangled_name = name->Text();
253 if (demangled_name) {
254 strncpy(p_name, demangled_name, namelen-1);
255 p_name[namelen-1] = '\0';
256 }
257 delete name;
258 }
259 }
260
261 // Fallback: if demangling did not work, just provide the unmangled name.
262 if (p_name[0] == '\0') {
263 strncpy(p_name, buf, namelen-1);
286 extern "C"
287 int dladdr(void* addr, Dl_info* info) {
288
289 if (!addr) {
290 return 0;
291 }
292
293 assert(info, "");
294
295 int rc = 0;
296
297 const char* const ZEROSTRING = "";
298
299 // Always return a string, even if a "" one. Linux dladdr manpage
300 // does not say anything about returning NULL
301 info->dli_fname = ZEROSTRING;
302 info->dli_sname = ZEROSTRING;
303 info->dli_saddr = NULL;
304
305 address p = (address) addr;
306 loaded_module_t lm;
307 bool found = false;
308
309 enum { noclue, code, data } type = noclue;
310
311 trcVerbose("dladdr(%p)...", p);
312
313 // Note: input address may be a function. I accept both a pointer to
314 // the entry of a function and a pointer to the function decriptor.
315 // (see ppc64 ABI)
316 found = LoadedLibraries::find_for_text_address(p, &lm);
317 if (found) {
318 type = code;
319 }
320
321 if (!found) {
322 // Not a pointer into any text segment. Is it a function descriptor?
323 const FunctionDescriptor* const pfd = (const FunctionDescriptor*) p;
324 p = pfd->entry();
325 if (p) {
326 found = LoadedLibraries::find_for_text_address(p, &lm);
327 if (found) {
328 type = code;
329 }
330 }
331 }
332
333 if (!found) {
334 // Neither direct code pointer nor function descriptor. A data ptr?
335 p = (address)addr;
336 found = LoadedLibraries::find_for_data_address(p, &lm);
337 if (found) {
338 type = data;
339 }
340 }
341
342 // If we did find the shared library this address belongs to (either
343 // code or data segment) resolve library path and, if possible, the
344 // symbol name.
345 if (found) {
346
347 // No need to intern the libpath, that one is already interned one layer below.
348 info->dli_fname = lm.path;
349
350 if (type == code) {
351
352 // For code symbols resolve function name and displacement. Use
353 // displacement to calc start of function.
354 char funcname[256] = "";
355 int displacement = 0;
356
357 if (getFuncName((codeptr_t) p, funcname, sizeof(funcname), &displacement,
358 NULL, NULL, 0, false) == 0) {
359 if (funcname[0] != '\0') {
360 const char* const interned = dladdr_fixed_strings.intern(funcname);
361 info->dli_sname = interned;
362 trcVerbose("... function name: %s ...", interned);
363 }
364
365 // From the displacement calculate the start of the function.
366 if (displacement != -1) {
367 info->dli_saddr = p - displacement;
368 } else {
369 info->dli_saddr = p;
370 }
371 } else {
372
373 // No traceback table found. Just assume the pointer is it.
374 info->dli_saddr = p;
375
376 }
377
378 } else if (type == data) {
381 info->dli_saddr = p;
382
383 } else {
384 ShouldNotReachHere();
385 }
386
387 rc = 1; // success: return 1 [sic]
388
389 }
390
391 // sanity checks.
392 if (rc) {
393 assert(info->dli_fname, "");
394 assert(info->dli_sname, "");
395 assert(info->dli_saddr, "");
396 }
397
398 return rc; // error: return 0 [sic]
399
400 }
401
|