Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/os/aix/vm/porting_aix.cpp
32284 views
1
/*
2
* Copyright 2012, 2013 SAP AG. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
*
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*
23
*/
24
25
#include "asm/assembler.hpp"
26
#include "loadlib_aix.hpp"
27
#include "porting_aix.hpp"
28
#include "utilities/debug.hpp"
29
30
#include <demangle.h>
31
#include <sys/debug.h>
32
33
//////////////////////////////////
34
// Provide implementation for dladdr based on LoadedLibraries pool and
35
// traceback table scan (see getFuncName).
36
37
// Search traceback table in stack,
38
// return procedure name from trace back table.
39
#define MAX_FUNC_SEARCH_LEN 0x10000
40
// Any PC below this value is considered toast.
41
#define MINIMUM_VALUE_FOR_PC ((unsigned int*)0x1024)
42
43
#define PTRDIFF_BYTES(p1,p2) (((ptrdiff_t)p1) - ((ptrdiff_t)p2))
44
45
// Align a pointer without having to cast.
46
inline char* align_ptr_up(char* ptr, intptr_t alignment) {
47
return (char*) align_size_up((intptr_t)ptr, alignment);
48
}
49
50
// Trace if verbose to tty.
51
// I use these now instead of the Xtrace system because the latter is
52
// not available at init time, hence worthless. Until we fix this, all
53
// tracing here is done with -XX:+Verbose.
54
#define trcVerbose(fmt, ...) { \
55
if (Verbose) { \
56
fprintf(stderr, fmt, ##__VA_ARGS__); \
57
fputc('\n', stderr); fflush(stderr); \
58
} \
59
}
60
#define ERRBYE(s) { trcVerbose(s); return -1; }
61
62
// Unfortunately, the interface of dladdr makes the implementator
63
// responsible for maintaining memory for function name/library
64
// name. I guess this is because most OS's keep those values as part
65
// of the mapped executable image ready to use. On AIX, this doesn't
66
// work, so I have to keep the returned strings. For now, I do this in
67
// a primitive string map. Should this turn out to be a performance
68
// problem, a better hashmap has to be used.
69
class fixed_strings {
70
struct node {
71
char* v;
72
node* next;
73
};
74
75
node* first;
76
77
public:
78
79
fixed_strings() : first(0) {}
80
~fixed_strings() {
81
node* n = first;
82
while (n) {
83
node* p = n;
84
n = n->next;
85
free(p->v);
86
delete p;
87
}
88
}
89
90
char* intern(const char* s) {
91
for (node* n = first; n; n = n->next) {
92
if (strcmp(n->v, s) == 0) {
93
return n->v;
94
}
95
}
96
node* p = new node;
97
p->v = strdup(s);
98
p->next = first;
99
first = p;
100
return p->v;
101
}
102
};
103
104
static fixed_strings dladdr_fixed_strings;
105
106
// Given a code pointer, returns the function name and the displacement.
107
// Function looks for the traceback table at the end of the function.
108
extern "C" int getFuncName(
109
codeptr_t pc, // [in] program counter
110
char* p_name, size_t namelen, // [out] optional: function name ("" if not available)
111
int* p_displacement, // [out] optional: displacement (-1 if not available)
112
const struct tbtable** p_tb, // [out] optional: ptr to traceback table to get further
113
// information (NULL if not available)
114
char* p_errmsg, size_t errmsglen // [out] optional: user provided buffer for error messages
115
) {
116
struct tbtable* tb = 0;
117
unsigned int searchcount = 0;
118
119
// initialize output parameters
120
if (p_name && namelen > 0) {
121
*p_name = '\0';
122
}
123
if (p_errmsg && errmsglen > 0) {
124
*p_errmsg = '\0';
125
}
126
if (p_displacement) {
127
*p_displacement = -1;
128
}
129
if (p_tb) {
130
*p_tb = NULL;
131
}
132
133
// weed out obvious bogus states
134
if (pc < MINIMUM_VALUE_FOR_PC) {
135
ERRBYE("invalid program counter");
136
}
137
138
codeptr_t pc2 = pc;
139
140
// make sure the pointer is word aligned.
141
pc2 = (codeptr_t) align_ptr_up((char*)pc2, 4);
142
143
// Find start of traceback table.
144
// (starts after code, is marked by word-aligned (32bit) zeros)
145
while ((*pc2 != NULL) && (searchcount++ < MAX_FUNC_SEARCH_LEN)) {
146
pc2++;
147
}
148
if (*pc2 != 0) {
149
ERRBYE("could not find traceback table within 5000 bytes of program counter");
150
}
151
//
152
// Set up addressability to the traceback table
153
//
154
tb = (struct tbtable*) (pc2 + 1);
155
156
// Is this really a traceback table? No way to be sure but
157
// some indicators we can check.
158
if (tb->tb.lang >= 0xf && tb->tb.lang <= 0xfb) {
159
// Language specifiers, go from 0 (C) to 14 (Objective C).
160
// According to spec, 0xf-0xfa reserved, 0xfb-0xff reserved for ibm.
161
ERRBYE("not a traceback table");
162
}
163
164
// Existence of fields in the tbtable extension are contingent upon
165
// specific fields in the base table. Check for their existence so
166
// that we can address the function name if it exists.
167
pc2 = (codeptr_t) tb +
168
sizeof(struct tbtable_short)/sizeof(int);
169
if (tb->tb.fixedparms != 0 || tb->tb.floatparms != 0)
170
pc2++;
171
172
if (tb->tb.has_tboff == TRUE) {
173
174
// I want to know the displacement
175
const unsigned int tb_offset = *pc2;
176
codeptr_t start_of_procedure =
177
(codeptr_t)(((char*)tb) - 4 - tb_offset); // (-4 to omit leading 0000)
178
179
// Weed out the cases where we did find the wrong traceback table.
180
if (pc < start_of_procedure) {
181
ERRBYE("could not find (the real) traceback table within 5000 bytes of program counter");
182
}
183
184
// return the displacement
185
if (p_displacement) {
186
(*p_displacement) = (int) PTRDIFF_BYTES(pc, start_of_procedure);
187
}
188
189
pc2++;
190
} else {
191
// return -1 for displacement
192
if (p_displacement) {
193
(*p_displacement) = -1;
194
}
195
}
196
197
if (tb->tb.int_hndl == TRUE)
198
pc2++;
199
200
if (tb->tb.has_ctl == TRUE)
201
pc2 += (*pc2) + 1; // don't care
202
203
//
204
// return function name if it exists.
205
//
206
if (p_name && namelen > 0) {
207
if (tb->tb.name_present) {
208
char buf[256];
209
const short l = MIN2<short>(*((short*)pc2), sizeof(buf) - 1);
210
memcpy(buf, (char*)pc2 + sizeof(short), l);
211
buf[l] = '\0';
212
213
p_name[0] = '\0';
214
215
// If it is a C++ name, try and demangle it using the Demangle interface (see demangle.h).
216
char* rest;
217
Name* const name = Demangle(buf, rest);
218
if (name) {
219
const char* const demangled_name = name->Text();
220
if (demangled_name) {
221
strncpy(p_name, demangled_name, namelen-1);
222
p_name[namelen-1] = '\0';
223
}
224
delete name;
225
}
226
227
// Fallback: if demangling did not work, just provide the unmangled name.
228
if (p_name[0] == '\0') {
229
strncpy(p_name, buf, namelen-1);
230
p_name[namelen-1] = '\0';
231
}
232
233
} else {
234
strncpy(p_name, "<nameless function>", namelen-1);
235
p_name[namelen-1] = '\0';
236
}
237
}
238
// Return traceback table, if user wants it.
239
if (p_tb) {
240
(*p_tb) = tb;
241
}
242
243
return 0;
244
}
245
246
// Special implementation of dladdr for Aix based on LoadedLibraries
247
// Note: dladdr returns non-zero for ok, 0 for error!
248
// Note: dladdr is not posix, but a non-standard GNU extension. So this tries to
249
// fulfill the contract of dladdr on Linux (see http://linux.die.net/man/3/dladdr)
250
// Note: addr may be both an AIX function descriptor or a real code pointer
251
// to the entry of a function.
252
extern "C"
253
int dladdr(void* addr, Dl_info* info) {
254
255
if (!addr) {
256
return 0;
257
}
258
259
assert(info, "");
260
261
int rc = 0;
262
263
const char* const ZEROSTRING = "";
264
265
// Always return a string, even if a "" one. Linux dladdr manpage
266
// does not say anything about returning NULL
267
info->dli_fname = ZEROSTRING;
268
info->dli_sname = ZEROSTRING;
269
info->dli_saddr = NULL;
270
271
address p = (address) addr;
272
const LoadedLibraryModule* lib = NULL;
273
274
enum { noclue, code, data } type = noclue;
275
276
trcVerbose("dladdr(%p)...", p);
277
278
// Note: input address may be a function. I accept both a pointer to
279
// the entry of a function and a pointer to the function decriptor.
280
// (see ppc64 ABI)
281
lib = LoadedLibraries::find_for_text_address(p);
282
if (lib) {
283
type = code;
284
}
285
286
if (!lib) {
287
// Not a pointer into any text segment. Is it a function descriptor?
288
const FunctionDescriptor* const pfd = (const FunctionDescriptor*) p;
289
p = pfd->entry();
290
if (p) {
291
lib = LoadedLibraries::find_for_text_address(p);
292
if (lib) {
293
type = code;
294
}
295
}
296
}
297
298
if (!lib) {
299
// Neither direct code pointer nor function descriptor. A data ptr?
300
p = (address)addr;
301
lib = LoadedLibraries::find_for_data_address(p);
302
if (lib) {
303
type = data;
304
}
305
}
306
307
// If we did find the shared library this address belongs to (either
308
// code or data segment) resolve library path and, if possible, the
309
// symbol name.
310
if (lib) {
311
const char* const interned_libpath =
312
dladdr_fixed_strings.intern(lib->get_fullpath());
313
if (interned_libpath) {
314
info->dli_fname = interned_libpath;
315
}
316
317
if (type == code) {
318
319
// For code symbols resolve function name and displacement. Use
320
// displacement to calc start of function.
321
char funcname[256] = "";
322
int displacement = 0;
323
324
if (getFuncName((codeptr_t) p, funcname, sizeof(funcname), &displacement,
325
NULL, NULL, 0) == 0) {
326
if (funcname[0] != '\0') {
327
const char* const interned = dladdr_fixed_strings.intern(funcname);
328
info->dli_sname = interned;
329
trcVerbose("... function name: %s ...", interned);
330
}
331
332
// From the displacement calculate the start of the function.
333
if (displacement != -1) {
334
info->dli_saddr = p - displacement;
335
} else {
336
info->dli_saddr = p;
337
}
338
} else {
339
340
// No traceback table found. Just assume the pointer is it.
341
info->dli_saddr = p;
342
343
}
344
345
} else if (type == data) {
346
347
// For data symbols.
348
info->dli_saddr = p;
349
350
} else {
351
ShouldNotReachHere();
352
}
353
354
rc = 1; // success: return 1 [sic]
355
356
}
357
358
// sanity checks.
359
if (rc) {
360
assert(info->dli_fname, "");
361
assert(info->dli_sname, "");
362
assert(info->dli_saddr, "");
363
}
364
365
return rc; // error: return 0 [sic]
366
367
}
368
369