]>
Commit | Line | Data |
---|---|---|
283a159f AH |
1 | // name-finder.cc - Convert addresses to names |
2 | ||
3 | /* Copyright (C) 2000 Red Hat Inc | |
4 | ||
5 | This file is part of libgcj. | |
6 | ||
7 | This software is copyrighted work licensed under the terms of the | |
8 | Libgcj License. Please consult the file "LIBGCJ_LICENSE" for | |
9 | details. */ | |
10 | ||
11 | /** | |
12 | * @author Andrew Haley <aph@cygnus.com> | |
13 | * @date Jan 6 2000 | |
14 | */ | |
15 | ||
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. | |
19 | ||
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. */ | |
23 | ||
24 | ||
25 | #ifndef _GNU_SOURCE | |
26 | #define _GNU_SOURCE 1 | |
27 | #endif | |
28 | ||
29 | #include <config.h> | |
30 | ||
31 | #include <string.h> | |
32 | ||
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> | |
40 | ||
41 | #include <sys/types.h> | |
42 | ||
43 | #include <stdlib.h> | |
44 | #include <stdio.h> | |
45 | ||
46 | #ifdef HAVE_UNISTD_H | |
47 | #include <unistd.h> | |
48 | #endif | |
49 | ||
50 | #ifdef HAVE_DLFCN_H | |
51 | #include <dlfcn.h> | |
52 | #endif | |
53 | ||
54 | #include <name-finder.h> | |
55 | ||
56 | /* Create a new name finder which will perform address lookups on an | |
57 | executable. */ | |
58 | ||
59 | _Jv_name_finder::_Jv_name_finder (char *executable) | |
60 | { | |
61 | #if defined (HAVE_PIPE) && defined (HAVE_FORK) && defined (HAVE_EXECVP) | |
62 | error = 0; | |
63 | ||
64 | char *argv[6]; | |
65 | { | |
66 | int arg = 0; | |
6c80c45e TT |
67 | #ifdef __ia64__ |
68 | argv[arg++] = "addr2name.awk"; | |
69 | #else | |
283a159f AH |
70 | argv[arg++] = "addr2line"; |
71 | argv[arg++] = "-C"; | |
72 | argv[arg++] = "-f"; | |
73 | argv[arg++] = "-e"; | |
6c80c45e | 74 | #endif |
283a159f AH |
75 | argv[arg++] = executable; |
76 | argv[arg] = NULL; | |
77 | } | |
78 | ||
79 | error |= pipe (f_pipe) < 0; | |
80 | error |= pipe (b_pipe) < 0; | |
efc70584 | 81 | |
283a159f AH |
82 | if (error) |
83 | return; | |
84 | ||
85 | pid = fork (); | |
86 | if (pid == 0) | |
87 | { | |
88 | close (f_pipe[1]); | |
89 | close (b_pipe[0]); | |
90 | dup2 (f_pipe[0], fileno (stdin)); | |
91 | dup2 (b_pipe[1], fileno (stdout)); | |
92 | execvp (argv[0], argv); | |
93 | _exit (127); | |
94 | } | |
efc70584 | 95 | |
283a159f AH |
96 | close (f_pipe [0]); |
97 | close (b_pipe [1]); | |
efc70584 | 98 | |
283a159f AH |
99 | if (pid < 0) |
100 | { | |
101 | error |= 1; | |
102 | return; | |
103 | } | |
efc70584 | 104 | |
283a159f AH |
105 | b_pipe_fd = fdopen (b_pipe[0], "r"); |
106 | error |= !b_pipe_fd; | |
107 | #endif | |
108 | } | |
109 | ||
110 | /* Convert a pointer to hex. */ | |
111 | ||
112 | void | |
113 | _Jv_name_finder::toHex (void *p) | |
114 | { | |
115 | unsigned long long n = (unsigned long long)p; | |
116 | int digits = sizeof (void *) * 2; | |
117 | ||
118 | strcpy (hex, "0x"); | |
119 | for (int i = digits - 1; i >= 0; i--) | |
120 | { | |
121 | int digit = n % 16; | |
122 | ||
123 | n /= 16; | |
124 | hex[i+2] = digit > 9 ? 'a' + digit - 10 : '0' + digit; | |
125 | } | |
126 | hex [digits+2] = 0; | |
127 | } | |
128 | ||
129 | /* Given a pointer to a function or method, try to convert it into a | |
130 | name and the appropriate line and source file. The caller passes | |
131 | the code pointer in p. | |
132 | ||
133 | Returns false if the lookup fails. Even if this happens, the field | |
134 | he will have been correctly filled in with the pointer. */ | |
135 | ||
136 | bool | |
137 | _Jv_name_finder::lookup (void *p) | |
138 | { | |
6a3bad7d | 139 | extern char **_Jv_argv; |
283a159f AH |
140 | toHex (p); |
141 | ||
b9f243c2 | 142 | #if defined (HAVE_DLFCN_H) && defined (HAVE_DLADDR) |
283a159f AH |
143 | { |
144 | Dl_info dl_info; | |
145 | ||
146 | if (dladdr (p, &dl_info)) | |
147 | { | |
148 | strncpy (file_name, dl_info.dli_fname, sizeof file_name); | |
149 | strncpy (method_name, dl_info.dli_sname, sizeof method_name); | |
6a3bad7d BM |
150 | |
151 | /* Don't trust dladdr() if the address is from the main program. */ | |
abb32cf5 | 152 | if (_Jv_argv == NULL || strcmp (file_name, _Jv_argv[0]) != 0) |
6a3bad7d | 153 | return true; |
283a159f AH |
154 | } |
155 | } | |
156 | #endif | |
157 | ||
158 | #if defined (HAVE_PIPE) && defined (HAVE_FORK) && defined (HAVE_EXECVP) | |
159 | if (error) | |
160 | return false; | |
161 | ||
162 | error |= write (f_pipe[1], hex, strlen (hex)) < 0; | |
163 | if (error) | |
164 | return false; | |
165 | error |= write (f_pipe[1], "\n", 1) < 0; | |
166 | if (error) | |
167 | return false; | |
168 | ||
169 | error |= (fgets (method_name, sizeof method_name, b_pipe_fd) == NULL); | |
170 | if (error) | |
171 | return false; | |
172 | error |= (fgets (file_name, sizeof file_name, b_pipe_fd) == NULL); | |
173 | if (error) | |
174 | return false; | |
175 | ||
176 | char *newline = strchr (method_name, '\n'); | |
177 | if (newline) | |
178 | *newline = 0; | |
179 | newline = strchr (file_name, '\n'); | |
180 | if (newline) | |
181 | *newline = 0; | |
182 | ||
183 | return true; | |
184 | ||
185 | #else | |
186 | return false; | |
187 | #endif /* defined (HAVE_PIPE) && defined (HAVE_FORK) && defined (HAVE_EXECVP) */ | |
188 | } |