1 /* |
1 /* |
2 * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. |
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. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * |
4 * |
5 * This code is free software; you can redistribute it and/or modify it |
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 |
6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. |
7 * published by the Free Software Foundation. |
24 #include <stdarg.h> |
24 #include <stdarg.h> |
25 #include <stdio.h> |
25 #include <stdio.h> |
26 #include <stdlib.h> |
26 #include <stdlib.h> |
27 #include <string.h> |
27 #include <string.h> |
28 #include <fcntl.h> |
28 #include <fcntl.h> |
29 #include <thread_db.h> |
29 #include <sys/procfs.h> |
30 #include "libproc_impl.h" |
30 #include "libproc_impl.h" |
|
31 #include "proc_service.h" |
31 |
32 |
32 #define SA_ALTROOT "SA_ALTROOT" |
33 #define SA_ALTROOT "SA_ALTROOT" |
33 |
34 |
34 int pathmap_open(const char* name) { |
35 int pathmap_open(const char* name) { |
35 static const char *alt_root = NULL; |
36 static const char *alt_root = NULL; |
114 // initialize libproc |
115 // initialize libproc |
115 JNIEXPORT bool JNICALL |
116 JNIEXPORT bool JNICALL |
116 init_libproc(bool debug) { |
117 init_libproc(bool debug) { |
117 // init debug mode |
118 // init debug mode |
118 _libsaproc_debug = debug; |
119 _libsaproc_debug = debug; |
119 |
|
120 // initialize the thread_db library |
|
121 if (td_init() != TD_OK) { |
|
122 print_debug("libthread_db's td_init failed\n"); |
|
123 return false; |
|
124 } |
|
125 |
|
126 return true; |
120 return true; |
127 } |
121 } |
128 |
122 |
129 static void destroy_lib_info(struct ps_prochandle* ph) { |
123 static void destroy_lib_info(struct ps_prochandle* ph) { |
130 lib_info* lib = ph->libs; |
124 lib_info* lib = ph->libs; |
254 } |
248 } |
255 return NULL; |
249 return NULL; |
256 } |
250 } |
257 |
251 |
258 // add a thread to ps_prochandle |
252 // add a thread to ps_prochandle |
259 thread_info* add_thread_info(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id) { |
253 thread_info* add_thread_info(struct ps_prochandle* ph, lwpid_t lwp_id) { |
260 thread_info* newthr; |
254 thread_info* newthr; |
261 if ( (newthr = (thread_info*) calloc(1, sizeof(thread_info))) == NULL) { |
255 if ( (newthr = (thread_info*) calloc(1, sizeof(thread_info))) == NULL) { |
262 print_debug("can't allocate memory for thread_info\n"); |
256 print_debug("can't allocate memory for thread_info\n"); |
263 return NULL; |
257 return NULL; |
264 } |
258 } |
265 |
259 |
266 // initialize thread info |
260 // initialize thread info |
267 newthr->pthread_id = pthread_id; |
|
268 newthr->lwp_id = lwp_id; |
261 newthr->lwp_id = lwp_id; |
269 |
262 |
270 // add new thread to the list |
263 // add new thread to the list |
271 newthr->next = ph->threads; |
264 newthr->next = ph->threads; |
272 ph->threads = newthr; |
265 ph->threads = newthr; |
292 previous_thr->next = current_thr->next; |
285 previous_thr->next = current_thr->next; |
293 } |
286 } |
294 ph->num_threads--; |
287 ph->num_threads--; |
295 free(current_thr); |
288 free(current_thr); |
296 } |
289 } |
297 |
|
298 // struct used for client data from thread_db callback |
|
299 struct thread_db_client_data { |
|
300 struct ps_prochandle* ph; |
|
301 thread_info_callback callback; |
|
302 }; |
|
303 |
|
304 // callback function for libthread_db |
|
305 static int thread_db_callback(const td_thrhandle_t *th_p, void *data) { |
|
306 struct thread_db_client_data* ptr = (struct thread_db_client_data*) data; |
|
307 td_thrinfo_t ti; |
|
308 td_err_e err; |
|
309 |
|
310 memset(&ti, 0, sizeof(ti)); |
|
311 err = td_thr_get_info(th_p, &ti); |
|
312 if (err != TD_OK) { |
|
313 print_debug("libthread_db : td_thr_get_info failed, can't get thread info\n"); |
|
314 return err; |
|
315 } |
|
316 |
|
317 print_debug("thread_db : pthread %d (lwp %d)\n", ti.ti_tid, ti.ti_lid); |
|
318 |
|
319 if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE) { |
|
320 print_debug("Skipping pthread %d (lwp %d)\n", ti.ti_tid, ti.ti_lid); |
|
321 return TD_OK; |
|
322 } |
|
323 |
|
324 if (ptr->callback(ptr->ph, ti.ti_tid, ti.ti_lid) != true) |
|
325 return TD_ERR; |
|
326 |
|
327 return TD_OK; |
|
328 } |
|
329 |
|
330 // read thread_info using libthread_db |
|
331 bool read_thread_info(struct ps_prochandle* ph, thread_info_callback cb) { |
|
332 struct thread_db_client_data mydata; |
|
333 td_thragent_t* thread_agent = NULL; |
|
334 if (td_ta_new(ph, &thread_agent) != TD_OK) { |
|
335 print_debug("can't create libthread_db agent\n"); |
|
336 return false; |
|
337 } |
|
338 |
|
339 mydata.ph = ph; |
|
340 mydata.callback = cb; |
|
341 |
|
342 // we use libthread_db iterator to iterate thru list of threads. |
|
343 if (td_ta_thr_iter(thread_agent, thread_db_callback, &mydata, |
|
344 TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY, |
|
345 TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS) != TD_OK) { |
|
346 td_ta_delete(thread_agent); |
|
347 return false; |
|
348 } |
|
349 |
|
350 // delete thread agent |
|
351 td_ta_delete(thread_agent); |
|
352 return true; |
|
353 } |
|
354 |
|
355 |
290 |
356 // get number of threads |
291 // get number of threads |
357 int get_num_threads(struct ps_prochandle* ph) { |
292 int get_num_threads(struct ps_prochandle* ph) { |
358 return ph->num_threads; |
293 return ph->num_threads; |
359 } |
294 } |
482 ps_lgetregs(struct ps_prochandle *ph, lwpid_t lid, prgregset_t gregset) { |
417 ps_lgetregs(struct ps_prochandle *ph, lwpid_t lid, prgregset_t gregset) { |
483 print_debug("ps_lgetfpregs not implemented\n"); |
418 print_debug("ps_lgetfpregs not implemented\n"); |
484 return PS_OK; |
419 return PS_OK; |
485 } |
420 } |
486 |
421 |
487 // new libthread_db of NPTL seem to require this symbol |
|
488 JNIEXPORT ps_err_e JNICALL |
|
489 ps_get_thread_area() { |
|
490 print_debug("ps_get_thread_area not implemented\n"); |
|
491 return PS_OK; |
|
492 } |
|