OSDN Git Service

8f0cdf40a970ac71b518105f7766f1a44b419d9b
[pf3gnuchains/gcc-fork.git] / libjava / name-finder.cc
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;
67     argv[arg++] = "addr2line";
68     argv[arg++] = "-C";
69     argv[arg++] = "-f";
70     argv[arg++] = "-e";
71     argv[arg++] = executable;
72     argv[arg] = NULL;
73   }
74
75   error |= pipe (f_pipe) < 0;
76   error |= pipe (b_pipe) < 0;
77       
78   if (error)
79     return;
80
81   pid = fork ();
82   if (pid == 0)
83     {
84       close (f_pipe[1]);
85       close (b_pipe[0]);
86       dup2 (f_pipe[0], fileno (stdin));
87       dup2 (b_pipe[1], fileno (stdout));
88       execvp (argv[0], argv);
89       _exit (127);
90     }
91       
92   close (f_pipe [0]);
93   close (b_pipe [1]);
94       
95   if (pid < 0)
96     {
97       error |= 1; 
98       return;
99     }
100       
101   b_pipe_fd = fdopen (b_pipe[0], "r");
102   error |= !b_pipe_fd;
103 #endif
104 }
105
106 /* Convert a pointer to hex. */
107
108 void
109 _Jv_name_finder::toHex (void *p)
110 {
111   unsigned long long n = (unsigned long long)p;
112   int digits = sizeof (void *) * 2;
113
114   strcpy (hex, "0x");
115   for (int i = digits - 1; i >= 0; i--)
116     {
117       int digit = n % 16;
118       
119       n /= 16;
120       hex[i+2] = digit > 9 ? 'a' + digit - 10 : '0' + digit; 
121     }
122   hex [digits+2] = 0;
123 }   
124
125 /* Given a pointer to a function or method, try to convert it into a
126    name and the appropriate line and source file.  The caller passes
127    the code pointer in p.
128
129    Returns false if the lookup fails.  Even if this happens, the field
130    he will have been correctly filled in with the pointer.  */
131
132 bool
133 _Jv_name_finder::lookup (void *p)
134 {
135   toHex (p);
136       
137 #if defined (HAVE_DLFCN_H) && defined (HAVE_DLADDR)
138   {
139     Dl_info dl_info;
140     
141     if (dladdr (p, &dl_info))
142       {
143         strncpy (file_name, dl_info.dli_fname, sizeof file_name);
144         strncpy (method_name, dl_info.dli_sname, sizeof method_name);
145         return true;
146       }
147   }
148 #endif
149
150 #if defined (HAVE_PIPE) && defined (HAVE_FORK) && defined (HAVE_EXECVP)
151   if (error)
152     return false;
153
154   error |= write (f_pipe[1], hex, strlen (hex)) < 0;
155   if (error)
156     return false;
157   error |= write (f_pipe[1], "\n", 1) < 0;
158   if (error)
159     return false;
160
161   error |= (fgets (method_name, sizeof method_name, b_pipe_fd) == NULL);
162   if (error)
163     return false;
164   error |= (fgets (file_name, sizeof file_name, b_pipe_fd) == NULL);
165   if (error)
166     return false;
167
168   char *newline = strchr (method_name, '\n');
169   if (newline)
170     *newline = 0;
171   newline = strchr (file_name, '\n');
172   if (newline)
173     *newline = 0;
174
175   return true;
176
177 #else
178   return false;
179 #endif /* defined (HAVE_PIPE) && defined (HAVE_FORK) && defined (HAVE_EXECVP) */
180 }