1 // natNameFinder.cc - native helper methods for NameFinder.java
2 
3 /* Copyright (C) 2002, 2003  Free Software Foundation, 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 Mark Wielaard (mark@klomp.org)
13  * Based on the old name-finder.cc by Andrew Haley <aph@cygnus.com>.
14  */
15 
16 #include <config.h>
17 
18 #include <string.h>
19 
20 #include <gcj/cni.h>
21 #include <jvm.h>
22 #include <java/lang/String.h>
23 #include <java/lang/StackTraceElement.h>
24 #include <java/lang/StringBuffer.h>
25 #include <java-interp.h>
26 
27 #include <gnu/gcj/runtime/NameFinder.h>
28 
29 #ifdef HAVE_DLFCN_H
30 #include <dlfcn.h>
31 #endif
32 
33 // On some systems, a prefix is attached to a method name before
34 // it is exported as a label. The GCC preprocessor predefines
35 // this prefix as the macro __USER_LABEL_PREFIX__ which expands to
36 // a string (not string constant) representing the prefix, if any.
37 #undef LABEL_PREFIX
38 #ifdef __USER_LABEL_PREFIX__
39 
40 #define USER_LABEL_PREFIX_STRING_0(s) #s
41 #define USER_LABEL_PREFIX_STRING(s) USER_LABEL_PREFIX_STRING_0(s)
42 
43 #define LABEL_PREFIX USER_LABEL_PREFIX_STRING(__USER_LABEL_PREFIX__)
44 
45 #else /* __USER_LABEL_PREFIX__ */
46 
47 #define LABEL_PREFIX ""
48 
49 #endif /* ! __USER_LABEL_PREFIX__ */
50 
51 java::lang::String*
getExternalLabel(java::lang::String * name)52 gnu::gcj::runtime::NameFinder::getExternalLabel (java::lang::String* name)
53 {
54   jsize nameLen = JvGetStringUTFLength (name);
55   jsize pfxLen = strlen (LABEL_PREFIX);
56   char *newName = (char *) JvMalloc (pfxLen + nameLen + 1);
57   *(newName + 0) = '\0';
58   strcpy (newName, LABEL_PREFIX);
59   JvGetStringUTFRegion (name, 0, name->length(), newName + pfxLen);
60   *(newName + pfxLen + nameLen) = '\0';
61   return JvNewStringLatin1 (newName);
62 }
63 
64 java::lang::String*
getExecutable(void)65 gnu::gcj::runtime::NameFinder::getExecutable (void)
66 {
67   return JvNewStringLatin1 (_Jv_ThisExecutable ());
68 }
69 
70 java::lang::String*
getAddrAsString(RawData * addrs,jint n)71 gnu::gcj::runtime::NameFinder::getAddrAsString(RawData* addrs, jint n)
72 {
73   _Jv_frame_info *p = (_Jv_frame_info *) addrs;
74   typedef unsigned word_t __attribute ((mode (word)));
75   word_t w = (word_t) p[n].addr;
76   int digits = sizeof (void *) * 2;
77   char hex[digits+5];
78 
79   strcpy (hex, "0x");
80   for (int i = digits - 1; i >= 0; i--)
81     {
82       int digit = w % 16;
83 
84       w /= 16;
85       hex[i+2] = digit > 9 ? 'a' + digit - 10 : '0' + digit;
86     }
87   hex [digits+2] = 0;
88 
89   return JvNewStringLatin1(hex);
90 }
91 
92 java::lang::StackTraceElement*
dladdrLookup(RawData * addrs,jint n)93 gnu::gcj::runtime::NameFinder::dladdrLookup(RawData* addrs, jint n)
94 {
95 #if defined (HAVE_DLFCN_H) && defined (HAVE_DLADDR)
96   extern char **_Jv_argv;
97   char name[1024];
98   char file_name[1024];
99   _Jv_frame_info *stack = (_Jv_frame_info *) addrs;
100   void* p = stack[n].addr;
101   Dl_info dl_info;
102 
103   if (dladdr (p, &dl_info))
104     {
105       if (dl_info.dli_fname)
106         strncpy (file_name, dl_info.dli_fname, sizeof file_name);
107       if (dl_info.dli_sname)
108         strncpy (name, dl_info.dli_sname, sizeof name);
109 
110      /* Don't trust dladdr() if the address is from the main program. */
111      if (dl_info.dli_fname != NULL
112          && dl_info.dli_sname != NULL
113          && (_Jv_argv == NULL || strcmp (file_name, _Jv_argv[0]) != 0))
114        return createStackTraceElement (JvNewStringLatin1 (name),
115 				       JvNewStringLatin1 (file_name));
116     }
117 #endif
118   return NULL;
119 }
120 
121 java::lang::StackTraceElement *
lookupInterp(RawData * addrs,jint n)122 gnu::gcj::runtime::NameFinder::lookupInterp(RawData* addrs, jint n)
123 {
124 #ifdef INTERPRETER
125   _Jv_frame_info *stack = (_Jv_frame_info *) addrs;
126   if (stack[n].interp == NULL)
127     return NULL;
128 
129   _Jv_InterpMethod *meth
130     = reinterpret_cast<_Jv_InterpMethod *> (stack[n].interp);
131   java::lang::StringBuffer *sb = new java::lang::StringBuffer();
132   sb->append(_Jv_NewStringUtf8Const(meth->self->name));
133   sb->append(_Jv_NewStringUtf8Const(meth->self->signature));
134   // FIXME: source file name and line number can be found from
135   // bytecode debug information.  But currently we don't keep that
136   // around.
137   // FIXME: is using the defining class correct here?
138   java::lang::String *className = meth->defining_class->getName();
139   java::lang::String *methodName
140 	  = demangleInterpreterMethod(sb->toString(), className);
141   return new java::lang::StackTraceElement(NULL, -1,
142 					   className, methodName, false);
143 #else // INTERPRETER
144   return NULL;
145 #endif // INTERPRETER
146 }
147