1 // name-finder.cc - Convert addresses to names
3 /* Copyright (C) 2000, 2002 Free Software Foundation, Inc
5 This file is part of libgcj.
7 This software is copyrighted work licensed under the terms of the
8 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
12 * @author Andrew Haley <aph@cygnus.com>
16 /* _Jv_name_finder is a class wrapper around a mechanism that can
17 convert address of methods to their names and the names of files in
20 Right now, the only implementation of this involves running a copy
21 of addr2line, but at some point it is worth building this
22 functionality into libgcj, if only for embedded systems. */
35 #include <java/lang/Object.h>
36 #include <java-threads.h>
37 #include <java/lang/Throwable.h>
38 #include <java/io/PrintStream.h>
39 #include <java/io/PrintWriter.h>
41 #include <sys/types.h>
54 #include <name-finder.h>
56 /* Create a new name finder which will perform address lookups on an
59 _Jv_name_finder::_Jv_name_finder (char *executable
)
61 #if defined (HAVE_PIPE) && defined (HAVE_FORK) && defined (HAVE_EXECVP)
62 demangling_error
= lookup_error
= 0;
64 // Initialize file descriptors so that shutdown works properly.
77 // addr2line helper process.
83 argv
[arg
++] = "addr2name.awk";
85 argv
[arg
++] = "addr2line";
89 argv
[arg
++] = executable
;
93 lookup_error
|= pipe (f_pipe
) < 0;
94 lookup_error
|= pipe (b_pipe
) < 0;
104 dup2 (f_pipe
[0], fileno (stdin
));
105 dup2 (b_pipe
[1], fileno (stdout
));
106 execvp (argv
[0], argv
);
110 // Close child end of pipes. Set local descriptors to -1 so we
111 // don't try to close the fd again.
123 b_pipe_fd
= fdopen (b_pipe
[0], "r");
124 lookup_error
|= !b_pipe_fd
;
128 // Don't try to close the fd twice.
132 // c++filt helper process.
135 argv2
[0] = "c++filt";
140 demangling_error
|= pipe (f2_pipe
) < 0;
141 demangling_error
|= pipe (b2_pipe
) < 0;
143 if (demangling_error
)
151 dup2 (f2_pipe
[0], fileno (stdin
));
152 dup2 (b2_pipe
[1], fileno (stdout
));
153 execvp (argv2
[0], argv2
);
157 // Close child end of pipes. Set local descriptors to -1 so we
158 // don't try to close the fd again.
166 demangling_error
|= 1;
170 b2_pipe_fd
= fdopen (b2_pipe
[0], "r");
171 demangling_error
|= !b2_pipe_fd
;
173 if (! demangling_error
)
175 // Don't try to close the fd twice.
181 /* Convert a pointer to hex. */
184 _Jv_name_finder::toHex (void *p
)
186 typedef unsigned word_t
__attribute ((mode (word
)));
187 word_t n
= (word_t
) p
;
188 int digits
= sizeof (void *) * 2;
191 for (int i
= digits
- 1; i
>= 0; i
--)
196 hex
[i
+2] = digit
> 9 ? 'a' + digit
- 10 : '0' + digit
;
201 /* Creates a StackTraceElement given a string and a filename.
202 Splits the given string into the class and method part.
203 The string s will be a demangled to a fully qualified java method string.
204 The string f will be decomposed into a file name and a possible line number.
205 The given strings will be altered. */
207 java::lang::StackTraceElement
*
208 _Jv_name_finder::createStackTraceElement(char *s
, char *f
)
211 char *class_name
= NULL
;
212 char *method_name
= NULL
;
214 #if defined (HAVE_PIPE) && defined (HAVE_FORK) && defined (HAVE_EXECVP)
215 if (demangling_error
)
218 demangling_error
|= write (f2_pipe
[1], s
, strlen (s
)) < 0;
219 if (demangling_error
)
221 demangling_error
|= write (f2_pipe
[1], "\n", 1) < 0;
222 if (demangling_error
)
226 demangling_error
|= (fgets (name
, sizeof name
, b2_pipe_fd
) == NULL
);
227 if (demangling_error
)
230 c
= strchr (name
, '\n');
263 c
= strrchr (f
, ':');
267 line_number
= atoi(c
+1);
275 c
= strchr (f
, '\n');
281 return new java::lang::StackTraceElement(
282 f
? JvNewStringLatin1 (f
) : NULL
,
284 class_name
? JvNewStringLatin1 (class_name
) : NULL
,
285 JvNewStringLatin1 (method_name
? method_name
: s
),
289 /* Given a pointer to a function or method, try to convert it into a
290 name and the appropriate line and source file. The caller passes
291 the code pointer in p.
293 Returns false if the lookup fails. Even if this happens, the field
294 he will have been correctly filled in with the pointer. */
296 java::lang::StackTraceElement
*
297 _Jv_name_finder::lookup (void *p
)
299 extern char **_Jv_argv
;
303 char file_name
[1024];
307 #if defined (HAVE_DLFCN_H) && defined (HAVE_DLADDR)
311 if (dladdr (p
, &dl_info
))
313 if (dl_info
.dli_fname
)
314 strncpy (file_name
, dl_info
.dli_fname
, sizeof file_name
);
315 if (dl_info
.dli_sname
)
316 strncpy (name
, dl_info
.dli_sname
, sizeof name
);
318 /* Don't trust dladdr() if the address is from the main program. */
319 if (dl_info
.dli_fname
!= NULL
320 && dl_info
.dli_sname
!= NULL
321 && (_Jv_argv
== NULL
|| strcmp (file_name
, _Jv_argv
[0]) != 0))
322 return createStackTraceElement (name
, file_name
);
327 memcpy (name
, hex
, strlen (hex
) + 1);
329 #if defined (HAVE_PIPE) && defined (HAVE_FORK) && defined (HAVE_EXECVP)
333 lookup_error
|= write (f_pipe
[1], hex
, strlen (hex
)) < 0;
336 lookup_error
|= write (f_pipe
[1], "\n", 1) < 0;
340 lookup_error
|= (fgets (name
, sizeof name
, b_pipe_fd
) == NULL
);
343 lookup_error
|= (fgets (file_name
, sizeof file_name
, b_pipe_fd
) == NULL
);
348 char *newline
= strchr (name
, '\n');
352 #endif /* defined (HAVE_PIPE) && defined (HAVE_FORK) && defined (HAVE_EXECVP) */
355 return (createStackTraceElement (name
, file_name
));