mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			193 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			193 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			C++
		
	
	
	
| // name-finder.cc - Convert addresses to names
 | |
| 
 | |
| /* Copyright (C) 2000  Red Hat Inc
 | |
| 
 | |
|    This file is part of libgcj.
 | |
| 
 | |
| This software is copyrighted work licensed under the terms of the
 | |
| Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
 | |
| details.  */
 | |
| 
 | |
| /**
 | |
|  * @author Andrew Haley <aph@cygnus.com>
 | |
|  * @date Jan 6  2000
 | |
|  */
 | |
| 
 | |
| /* _Jv_name_finder is a class wrapper around a mechanism that can
 | |
|    convert address of methods to their names and the names of files in
 | |
|    which they appear.
 | |
| 
 | |
|    Right now, the only implementation of this involves running a copy
 | |
|    of addr2line, but at some point it is worth building this
 | |
|    functionality into libgcj, if only for embedded systems.  */
 | |
| 
 | |
| 
 | |
| #ifndef _GNU_SOURCE
 | |
| #define _GNU_SOURCE 1
 | |
| #endif
 | |
| 
 | |
| #include <config.h>
 | |
| 
 | |
| #include <string.h>
 | |
| 
 | |
| #include <gcj/cni.h>
 | |
| #include <jvm.h>
 | |
| #include <java/lang/Object.h>
 | |
| #include <java-threads.h>
 | |
| #include <java/lang/Throwable.h>
 | |
| #include <java/io/PrintStream.h>
 | |
| #include <java/io/PrintWriter.h>
 | |
| 
 | |
| #include <sys/types.h>
 | |
| 
 | |
| #include <stdlib.h>
 | |
| #include <stdio.h>
 | |
| 
 | |
| #ifdef HAVE_UNISTD_H
 | |
| #include <unistd.h>
 | |
| #endif
 | |
| 
 | |
| #ifdef HAVE_DLFCN_H
 | |
| #include <dlfcn.h>
 | |
| #endif
 | |
| 
 | |
| #include <name-finder.h>
 | |
| 
 | |
| /* Create a new name finder which will perform address lookups on an
 | |
|    executable. */
 | |
| 
 | |
| _Jv_name_finder::_Jv_name_finder (char *executable)
 | |
| {
 | |
| #if defined (HAVE_PIPE) && defined (HAVE_FORK) && defined (HAVE_EXECVP)
 | |
|   error = 0;
 | |
| 
 | |
|   char *argv[6];
 | |
|   {
 | |
|     int arg = 0;
 | |
| #ifdef __ia64__
 | |
|     argv[arg++] = "addr2name.awk";
 | |
| #else
 | |
|     argv[arg++] = "addr2line";
 | |
|     argv[arg++] = "-C";
 | |
|     argv[arg++] = "-f";
 | |
|     argv[arg++] = "-e";
 | |
| #endif
 | |
|     argv[arg++] = executable;
 | |
|     argv[arg] = NULL;
 | |
|   }
 | |
| 
 | |
|   error |= pipe (f_pipe) < 0;
 | |
|   error |= pipe (b_pipe) < 0;
 | |
| 
 | |
|   if (error)
 | |
|     return;
 | |
| 
 | |
|   pid = fork ();
 | |
|   if (pid == 0)
 | |
|     {
 | |
|       close (f_pipe[1]);
 | |
|       close (b_pipe[0]);
 | |
|       dup2 (f_pipe[0], fileno (stdin));
 | |
|       dup2 (b_pipe[1], fileno (stdout));
 | |
|       execvp (argv[0], argv);
 | |
|       _exit (127);
 | |
|     }
 | |
| 
 | |
|   close (f_pipe [0]);
 | |
|   close (b_pipe [1]);
 | |
| 
 | |
|   if (pid < 0)
 | |
|     {
 | |
|       error |= 1; 
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|   b_pipe_fd = fdopen (b_pipe[0], "r");
 | |
|   error |= !b_pipe_fd;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /* Convert a pointer to hex. */
 | |
| 
 | |
| void
 | |
| _Jv_name_finder::toHex (void *p)
 | |
| {
 | |
|   unsigned long long n = (unsigned long long)p;
 | |
|   int digits = sizeof (void *) * 2;
 | |
| 
 | |
|   strcpy (hex, "0x");
 | |
|   for (int i = digits - 1; i >= 0; i--)
 | |
|     {
 | |
|       int digit = n % 16;
 | |
|       
 | |
|       n /= 16;
 | |
|       hex[i+2] = digit > 9 ? 'a' + digit - 10 : '0' + digit; 
 | |
|     }
 | |
|   hex [digits+2] = 0;
 | |
| }   
 | |
| 
 | |
| /* Given a pointer to a function or method, try to convert it into a
 | |
|    name and the appropriate line and source file.  The caller passes
 | |
|    the code pointer in p.
 | |
| 
 | |
|    Returns false if the lookup fails.  Even if this happens, the field
 | |
|    he will have been correctly filled in with the pointer.  */
 | |
| 
 | |
| bool
 | |
| _Jv_name_finder::lookup (void *p)
 | |
| {
 | |
|   extern char **_Jv_argv;
 | |
|   toHex (p);
 | |
|       
 | |
| #if defined (HAVE_DLFCN_H) && defined (HAVE_DLADDR)
 | |
|   {
 | |
|     Dl_info dl_info;
 | |
|     
 | |
|     if (dladdr (p, &dl_info))
 | |
|       {
 | |
|         if (dl_info.dli_fname)
 | |
| 	  strncpy (file_name, dl_info.dli_fname, sizeof file_name);
 | |
| 	if (dl_info.dli_sname)
 | |
| 	  strncpy (method_name, dl_info.dli_sname, sizeof method_name);
 | |
|        
 | |
|        /* Don't trust dladdr() if the address is from the main program. */
 | |
|        if (dl_info.dli_fname != NULL
 | |
|            && dl_info.dli_sname != NULL
 | |
| 	   && (_Jv_argv == NULL || strcmp (file_name, _Jv_argv[0]) != 0))
 | |
|          return true;
 | |
|       }
 | |
|   }
 | |
| #endif
 | |
| 
 | |
| #if defined (HAVE_PIPE) && defined (HAVE_FORK) && defined (HAVE_EXECVP)
 | |
|   if (error)
 | |
|     return false;
 | |
| 
 | |
|   error |= write (f_pipe[1], hex, strlen (hex)) < 0;
 | |
|   if (error)
 | |
|     return false;
 | |
|   error |= write (f_pipe[1], "\n", 1) < 0;
 | |
|   if (error)
 | |
|     return false;
 | |
| 
 | |
|   error |= (fgets (method_name, sizeof method_name, b_pipe_fd) == NULL);
 | |
|   if (error)
 | |
|     return false;
 | |
|   error |= (fgets (file_name, sizeof file_name, b_pipe_fd) == NULL);
 | |
|   if (error)
 | |
|     return false;
 | |
| 
 | |
|   char *newline = strchr (method_name, '\n');
 | |
|   if (newline)
 | |
|     *newline = 0;
 | |
|   newline = strchr (file_name, '\n');
 | |
|   if (newline)
 | |
|     *newline = 0;
 | |
| 
 | |
|   return true;
 | |
| 
 | |
| #else
 | |
|   return false;
 | |
| #endif /* defined (HAVE_PIPE) && defined (HAVE_FORK) && defined (HAVE_EXECVP) */
 | |
| }
 |