Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-aarch32-jdk8u
Path: blob/jdk8u272-b10-aarch32-20201026/hotspot/agent/src/os/linux/libproc_impl.c
48792 views
1
/*
2
* Copyright (c) 2003, 2019, Oracle and/or its affiliates. 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
#include <stdarg.h>
25
#include <stdio.h>
26
#include <stdlib.h>
27
#include <string.h>
28
#include <fcntl.h>
29
#include <thread_db.h>
30
#include "libproc_impl.h"
31
32
#define SA_ALTROOT "SA_ALTROOT"
33
34
int pathmap_open(const char* name) {
35
static const char *alt_root = NULL;
36
static int alt_root_initialized = 0;
37
38
int fd;
39
char alt_path[PATH_MAX + 1], *alt_path_end;
40
const char *s;
41
42
if (!alt_root_initialized) {
43
alt_root_initialized = -1;
44
alt_root = getenv(SA_ALTROOT);
45
}
46
47
if (alt_root == NULL) {
48
return open(name, O_RDONLY);
49
}
50
51
strcpy(alt_path, alt_root);
52
alt_path_end = alt_path + strlen(alt_path);
53
54
// Strip path items one by one and try to open file with alt_root prepended
55
s = name;
56
while (1) {
57
strcat(alt_path, s);
58
s += 1;
59
60
fd = open(alt_path, O_RDONLY);
61
if (fd >= 0) {
62
print_debug("path %s substituted for %s\n", alt_path, name);
63
return fd;
64
}
65
66
// Linker always put full path to solib to process, so we can rely
67
// on presence of /. If slash is not present, it means, that SOlib doesn't
68
// physically exist (e.g. linux-gate.so) and we fail opening it anyway
69
if ((s = strchr(s, '/')) == NULL) {
70
break;
71
}
72
73
*alt_path_end = 0;
74
}
75
76
return -1;
77
}
78
79
static bool _libsaproc_debug;
80
81
void print_debug(const char* format,...) {
82
if (_libsaproc_debug) {
83
va_list alist;
84
85
va_start(alist, format);
86
fputs("libsaproc DEBUG: ", stderr);
87
vfprintf(stderr, format, alist);
88
va_end(alist);
89
}
90
}
91
92
void print_error(const char* format,...) {
93
va_list alist;
94
va_start(alist, format);
95
fputs("ERROR: ", stderr);
96
vfprintf(stderr, format, alist);
97
va_end(alist);
98
}
99
100
bool is_debug() {
101
return _libsaproc_debug;
102
}
103
104
// initialize libproc
105
bool init_libproc(bool debug) {
106
// init debug mode
107
_libsaproc_debug = debug;
108
109
// initialize the thread_db library
110
if (td_init() != TD_OK) {
111
print_debug("libthread_db's td_init failed\n");
112
return false;
113
}
114
115
return true;
116
}
117
118
static void destroy_lib_info(struct ps_prochandle* ph) {
119
lib_info* lib = ph->libs;
120
while (lib) {
121
lib_info *next = lib->next;
122
if (lib->symtab) {
123
destroy_symtab(lib->symtab);
124
}
125
free(lib);
126
lib = next;
127
}
128
}
129
130
static void destroy_thread_info(struct ps_prochandle* ph) {
131
thread_info* thr = ph->threads;
132
while (thr) {
133
thread_info *next = thr->next;
134
free(thr);
135
thr = next;
136
}
137
}
138
139
// ps_prochandle cleanup
140
141
// ps_prochandle cleanup
142
void Prelease(struct ps_prochandle* ph) {
143
// do the "derived class" clean-up first
144
ph->ops->release(ph);
145
destroy_lib_info(ph);
146
destroy_thread_info(ph);
147
free(ph);
148
}
149
150
lib_info* add_lib_info(struct ps_prochandle* ph, const char* libname, uintptr_t base) {
151
return add_lib_info_fd(ph, libname, -1, base);
152
}
153
154
lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd, uintptr_t base) {
155
lib_info* newlib;
156
157
if ( (newlib = (lib_info*) calloc(1, sizeof(struct lib_info))) == NULL) {
158
print_debug("can't allocate memory for lib_info\n");
159
return NULL;
160
}
161
162
if (strlen(libname) >= sizeof(newlib->name)) {
163
print_debug("libname %s too long\n", libname);
164
return NULL;
165
}
166
strcpy(newlib->name, libname);
167
168
newlib->base = base;
169
170
if (fd == -1) {
171
if ( (newlib->fd = pathmap_open(newlib->name)) < 0) {
172
print_debug("can't open shared object %s\n", newlib->name);
173
free(newlib);
174
return NULL;
175
}
176
} else {
177
newlib->fd = fd;
178
}
179
180
// check whether we have got an ELF file. /proc/<pid>/map
181
// gives out all file mappings and not just shared objects
182
if (is_elf_file(newlib->fd) == false) {
183
close(newlib->fd);
184
free(newlib);
185
return NULL;
186
}
187
188
newlib->symtab = build_symtab(newlib->fd, libname);
189
if (newlib->symtab == NULL) {
190
print_debug("symbol table build failed for %s\n", newlib->name);
191
}
192
193
// even if symbol table building fails, we add the lib_info.
194
// This is because we may need to read from the ELF file for core file
195
// address read functionality. lookup_symbol checks for NULL symtab.
196
if (ph->libs) {
197
ph->lib_tail->next = newlib;
198
ph->lib_tail = newlib;
199
} else {
200
ph->libs = ph->lib_tail = newlib;
201
}
202
ph->num_libs++;
203
204
return newlib;
205
}
206
207
// lookup for a specific symbol
208
uintptr_t lookup_symbol(struct ps_prochandle* ph, const char* object_name,
209
const char* sym_name) {
210
// ignore object_name. search in all libraries
211
// FIXME: what should we do with object_name?? The library names are obtained
212
// by parsing /proc/<pid>/maps, which may not be the same as object_name.
213
// What we need is a utility to map object_name to real file name, something
214
// dlopen() does by looking at LD_LIBRARY_PATH and /etc/ld.so.cache. For
215
// now, we just ignore object_name and do a global search for the symbol.
216
217
lib_info* lib = ph->libs;
218
while (lib) {
219
if (lib->symtab) {
220
uintptr_t res = search_symbol(lib->symtab, lib->base, sym_name, NULL);
221
if (res) return res;
222
}
223
lib = lib->next;
224
}
225
226
print_debug("lookup failed for symbol '%s' in obj '%s'\n",
227
sym_name, object_name);
228
return (uintptr_t) NULL;
229
}
230
231
232
const char* symbol_for_pc(struct ps_prochandle* ph, uintptr_t addr, uintptr_t* poffset) {
233
const char* res = NULL;
234
lib_info* lib = ph->libs;
235
while (lib) {
236
if (lib->symtab && addr >= lib->base) {
237
res = nearest_symbol(lib->symtab, addr - lib->base, poffset);
238
if (res) return res;
239
}
240
lib = lib->next;
241
}
242
return NULL;
243
}
244
245
// add a thread to ps_prochandle
246
thread_info* add_thread_info(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id) {
247
thread_info* newthr;
248
if ( (newthr = (thread_info*) calloc(1, sizeof(thread_info))) == NULL) {
249
print_debug("can't allocate memory for thread_info\n");
250
return NULL;
251
}
252
253
// initialize thread info
254
newthr->pthread_id = pthread_id;
255
newthr->lwp_id = lwp_id;
256
257
// add new thread to the list
258
newthr->next = ph->threads;
259
ph->threads = newthr;
260
ph->num_threads++;
261
return newthr;
262
}
263
264
void delete_thread_info(struct ps_prochandle* ph, thread_info* thr_to_be_removed) {
265
thread_info* current_thr = ph->threads;
266
267
if (thr_to_be_removed == ph->threads) {
268
ph->threads = ph->threads->next;
269
} else {
270
thread_info* previous_thr;
271
while (current_thr && current_thr != thr_to_be_removed) {
272
previous_thr = current_thr;
273
current_thr = current_thr->next;
274
}
275
if (current_thr == NULL) {
276
print_error("Could not find the thread to be removed");
277
return;
278
}
279
previous_thr->next = current_thr->next;
280
}
281
ph->num_threads--;
282
free(current_thr);
283
}
284
285
// struct used for client data from thread_db callback
286
struct thread_db_client_data {
287
struct ps_prochandle* ph;
288
thread_info_callback callback;
289
};
290
291
// callback function for libthread_db
292
static int thread_db_callback(const td_thrhandle_t *th_p, void *data) {
293
struct thread_db_client_data* ptr = (struct thread_db_client_data*) data;
294
td_thrinfo_t ti;
295
td_err_e err;
296
297
memset(&ti, 0, sizeof(ti));
298
err = td_thr_get_info(th_p, &ti);
299
if (err != TD_OK) {
300
print_debug("libthread_db : td_thr_get_info failed, can't get thread info\n");
301
return err;
302
}
303
304
print_debug("thread_db : pthread %d (lwp %d)\n", ti.ti_tid, ti.ti_lid);
305
306
if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE) {
307
print_debug("Skipping pthread %d (lwp %d)\n", ti.ti_tid, ti.ti_lid);
308
return TD_OK;
309
}
310
311
if (ptr->callback(ptr->ph, ti.ti_tid, ti.ti_lid) != true)
312
return TD_ERR;
313
314
return TD_OK;
315
}
316
317
// read thread_info using libthread_db
318
bool read_thread_info(struct ps_prochandle* ph, thread_info_callback cb) {
319
struct thread_db_client_data mydata;
320
td_thragent_t* thread_agent = NULL;
321
if (td_ta_new(ph, &thread_agent) != TD_OK) {
322
print_debug("can't create libthread_db agent\n");
323
return false;
324
}
325
326
mydata.ph = ph;
327
mydata.callback = cb;
328
329
// we use libthread_db iterator to iterate thru list of threads.
330
if (td_ta_thr_iter(thread_agent, thread_db_callback, &mydata,
331
TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
332
TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS) != TD_OK) {
333
td_ta_delete(thread_agent);
334
return false;
335
}
336
337
// delete thread agent
338
td_ta_delete(thread_agent);
339
return true;
340
}
341
342
343
// get number of threads
344
int get_num_threads(struct ps_prochandle* ph) {
345
return ph->num_threads;
346
}
347
348
// get lwp_id of n'th thread
349
lwpid_t get_lwp_id(struct ps_prochandle* ph, int index) {
350
int count = 0;
351
thread_info* thr = ph->threads;
352
while (thr) {
353
if (count == index) {
354
return thr->lwp_id;
355
}
356
count++;
357
thr = thr->next;
358
}
359
return -1;
360
}
361
362
// get regs for a given lwp
363
bool get_lwp_regs(struct ps_prochandle* ph, lwpid_t lwp_id, struct user_regs_struct* regs) {
364
return ph->ops->get_lwp_regs(ph, lwp_id, regs);
365
}
366
367
// get number of shared objects
368
int get_num_libs(struct ps_prochandle* ph) {
369
return ph->num_libs;
370
}
371
372
// get name of n'th solib
373
const char* get_lib_name(struct ps_prochandle* ph, int index) {
374
int count = 0;
375
lib_info* lib = ph->libs;
376
while (lib) {
377
if (count == index) {
378
return lib->name;
379
}
380
count++;
381
lib = lib->next;
382
}
383
return NULL;
384
}
385
386
// get base address of a lib
387
uintptr_t get_lib_base(struct ps_prochandle* ph, int index) {
388
int count = 0;
389
lib_info* lib = ph->libs;
390
while (lib) {
391
if (count == index) {
392
return lib->base;
393
}
394
count++;
395
lib = lib->next;
396
}
397
return (uintptr_t)NULL;
398
}
399
400
bool find_lib(struct ps_prochandle* ph, const char *lib_name) {
401
lib_info *p = ph->libs;
402
while (p) {
403
if (strcmp(p->name, lib_name) == 0) {
404
return true;
405
}
406
p = p->next;
407
}
408
return false;
409
}
410
411
//--------------------------------------------------------------------------
412
// proc service functions
413
414
// get process id
415
pid_t ps_getpid(struct ps_prochandle *ph) {
416
return ph->pid;
417
}
418
419
// ps_pglobal_lookup() looks up the symbol sym_name in the symbol table
420
// of the load object object_name in the target process identified by ph.
421
// It returns the symbol's value as an address in the target process in
422
// *sym_addr.
423
424
ps_err_e ps_pglobal_lookup(struct ps_prochandle *ph, const char *object_name,
425
const char *sym_name, psaddr_t *sym_addr) {
426
*sym_addr = (psaddr_t) lookup_symbol(ph, object_name, sym_name);
427
return (*sym_addr ? PS_OK : PS_NOSYM);
428
}
429
430
// read "size" bytes info "buf" from address "addr"
431
ps_err_e ps_pdread(struct ps_prochandle *ph, psaddr_t addr,
432
void *buf, size_t size) {
433
return ph->ops->p_pread(ph, (uintptr_t) addr, buf, size)? PS_OK: PS_ERR;
434
}
435
436
// write "size" bytes of data to debuggee at address "addr"
437
ps_err_e ps_pdwrite(struct ps_prochandle *ph, psaddr_t addr,
438
const void *buf, size_t size) {
439
return ph->ops->p_pwrite(ph, (uintptr_t)addr, buf, size)? PS_OK: PS_ERR;
440
}
441
442
// ------------------------------------------------------------------------
443
// Functions below this point are not yet implemented. They are here only
444
// to make the linker happy.
445
446
ps_err_e ps_lsetfpregs(struct ps_prochandle *ph, lwpid_t lid, const prfpregset_t *fpregs) {
447
print_debug("ps_lsetfpregs not implemented\n");
448
return PS_OK;
449
}
450
451
ps_err_e ps_lsetregs(struct ps_prochandle *ph, lwpid_t lid, const prgregset_t gregset) {
452
print_debug("ps_lsetregs not implemented\n");
453
return PS_OK;
454
}
455
456
ps_err_e ps_lgetfpregs(struct ps_prochandle *ph, lwpid_t lid, prfpregset_t *fpregs) {
457
print_debug("ps_lgetfpregs not implemented\n");
458
return PS_OK;
459
}
460
461
ps_err_e ps_lgetregs(struct ps_prochandle *ph, lwpid_t lid, prgregset_t gregset) {
462
print_debug("ps_lgetfpregs not implemented\n");
463
return PS_OK;
464
}
465
466
// new libthread_db of NPTL seem to require this symbol
467
ps_err_e ps_get_thread_area() {
468
print_debug("ps_get_thread_area not implemented\n");
469
return PS_OK;
470
}
471
472