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