* config/rs6000/rs6000.c (spe_init_builtins,
[official-gcc.git] / libjava / name-finder.cc
blob2d383aaa2508f5c1e5c928910e21fedd0ad5c290
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
9 details. */
11 /**
12 * @author Andrew Haley <aph@cygnus.com>
13 * @date Jan 6 2000
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
18 which they appear.
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. */
25 #ifndef _GNU_SOURCE
26 #define _GNU_SOURCE 1
27 #endif
29 #include <config.h>
31 #include <string.h>
33 #include <gcj/cni.h>
34 #include <jvm.h>
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>
43 #include <stdlib.h>
44 #include <stdio.h>
46 #ifdef HAVE_UNISTD_H
47 #include <unistd.h>
48 #endif
50 #ifdef HAVE_DLFCN_H
51 #include <dlfcn.h>
52 #endif
54 #include <name-finder.h>
56 /* Create a new name finder which will perform address lookups on an
57 executable. */
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.
65 f_pipe[0] = -1;
66 f_pipe[1] = -1;
67 b_pipe[0] = -1;
68 b_pipe[1] = -1;
69 b_pipe_fd = NULL;
71 f2_pipe[0] = -1;
72 f2_pipe[1] = -1;
73 b2_pipe[0] = -1;
74 b2_pipe[1] = -1;
75 b2_pipe_fd = NULL;
77 // addr2line helper process.
79 char *argv[5];
81 int arg = 0;
82 #ifdef __ia64__
83 argv[arg++] = "addr2name.awk";
84 #else
85 argv[arg++] = "addr2line";
86 argv[arg++] = "-f";
87 argv[arg++] = "-e";
88 #endif
89 argv[arg++] = executable;
90 argv[arg] = NULL;
93 lookup_error |= pipe (f_pipe) < 0;
94 lookup_error |= pipe (b_pipe) < 0;
96 if (lookup_error)
97 return;
99 pid = fork ();
100 if (pid == 0)
102 close (f_pipe[1]);
103 close (b_pipe[0]);
104 dup2 (f_pipe[0], fileno (stdin));
105 dup2 (b_pipe[1], fileno (stdout));
106 execvp (argv[0], argv);
107 _exit (127);
110 // Close child end of pipes. Set local descriptors to -1 so we
111 // don't try to close the fd again.
112 close (f_pipe [0]);
113 f_pipe[0] = -1;
114 close (b_pipe [1]);
115 b_pipe[1] = -1;
117 if (pid < 0)
119 lookup_error |= 1;
120 return;
123 b_pipe_fd = fdopen (b_pipe[0], "r");
124 lookup_error |= !b_pipe_fd;
126 if (! lookup_error)
128 // Don't try to close the fd twice.
129 b_pipe[0] = -1;
132 // c++filt helper process.
134 char *argv2[4];
135 argv2[0] = "c++filt";
136 argv2[1] = "-s";
137 argv2[2] = "java";
138 argv2[3] = NULL;
140 demangling_error |= pipe (f2_pipe) < 0;
141 demangling_error |= pipe (b2_pipe) < 0;
143 if (demangling_error)
144 return;
146 pid2 = fork ();
147 if (pid2 == 0)
149 close (f2_pipe[1]);
150 close (b2_pipe[0]);
151 dup2 (f2_pipe[0], fileno (stdin));
152 dup2 (b2_pipe[1], fileno (stdout));
153 execvp (argv2[0], argv2);
154 _exit (127);
157 // Close child end of pipes. Set local descriptors to -1 so we
158 // don't try to close the fd again.
159 close (f2_pipe [0]);
160 f2_pipe[0] = -1;
161 close (b2_pipe [1]);
162 b2_pipe[1] = -1;
164 if (pid2 < 0)
166 demangling_error |= 1;
167 return;
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.
176 b2_pipe[0] = -1;
178 #endif
181 /* Convert a pointer to hex. */
183 void
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;
190 strcpy (hex, "0x");
191 for (int i = digits - 1; i >= 0; i--)
193 int digit = n % 16;
195 n /= 16;
196 hex[i+2] = digit > 9 ? 'a' + digit - 10 : '0' + digit;
198 hex [digits+2] = 0;
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)
210 char *c;
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)
216 goto fail;
218 demangling_error |= write (f2_pipe[1], s, strlen (s)) < 0;
219 if (demangling_error)
220 goto fail;
221 demangling_error |= write (f2_pipe[1], "\n", 1) < 0;
222 if (demangling_error)
223 goto fail;
225 char name[1024];
226 demangling_error |= (fgets (name, sizeof name, b2_pipe_fd) == NULL);
227 if (demangling_error)
228 goto fail;
230 c = strchr (name, '\n');
231 if (c)
232 *c = 0;
233 s = name;
234 #endif
236 c = strchr (s, '(');
237 if (c)
239 while(c-->s)
240 if (*c == '.')
241 break;
243 if (*c == '.')
245 *c = 0;
246 class_name = s;
247 method_name = c+1;
249 else
251 class_name = NULL;
252 method_name = s;
255 else
257 class_name = NULL;
258 method_name = s;
261 // Get line number
262 int line_number;
263 c = strrchr (f, ':');
264 if (c)
266 if (c[1] != 0)
267 line_number = atoi(c+1);
268 else
269 line_number = -1;
270 *c = 0;
272 else
274 line_number = -1;
275 c = strchr (f, '\n');
276 if (c)
277 *c = 0;
280 fail:
281 return new java::lang::StackTraceElement(
282 f ? JvNewStringLatin1 (f) : NULL,
283 line_number,
284 class_name ? JvNewStringLatin1 (class_name) : NULL,
285 JvNewStringLatin1 (method_name ? method_name : s),
286 false);
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;
300 toHex (p);
302 char name[1024];
303 char file_name[1024];
305 file_name[0] = 0;
307 #if defined (HAVE_DLFCN_H) && defined (HAVE_DLADDR)
309 Dl_info dl_info;
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);
325 #endif
327 memcpy (name, hex, strlen (hex) + 1);
329 #if defined (HAVE_PIPE) && defined (HAVE_FORK) && defined (HAVE_EXECVP)
330 if (lookup_error)
331 goto fail;
333 lookup_error |= write (f_pipe[1], hex, strlen (hex)) < 0;
334 if (lookup_error)
335 goto fail;
336 lookup_error |= write (f_pipe[1], "\n", 1) < 0;
337 if (lookup_error)
338 goto fail;
340 lookup_error |= (fgets (name, sizeof name, b_pipe_fd) == NULL);
341 if (lookup_error)
342 goto fail;
343 lookup_error |= (fgets (file_name, sizeof file_name, b_pipe_fd) == NULL);
344 if (lookup_error)
345 goto fail;
348 char *newline = strchr (name, '\n');
349 if (newline)
350 *newline = 0;
352 #endif /* defined (HAVE_PIPE) && defined (HAVE_FORK) && defined (HAVE_EXECVP) */
354 fail:
355 return (createStackTraceElement (name, file_name));