Tue, 08 Aug 2017 15:57:29 +0800
merge
aoqi@0 | 1 | /* |
aoqi@0 | 2 | * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. |
aoqi@0 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
aoqi@0 | 4 | * |
aoqi@0 | 5 | * This code is free software; you can redistribute it and/or modify it |
aoqi@0 | 6 | * under the terms of the GNU General Public License version 2 only, as |
aoqi@0 | 7 | * published by the Free Software Foundation. |
aoqi@0 | 8 | * |
aoqi@0 | 9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
aoqi@0 | 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
aoqi@0 | 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
aoqi@0 | 12 | * version 2 for more details (a copy is included in the LICENSE file that |
aoqi@0 | 13 | * accompanied this code). |
aoqi@0 | 14 | * |
aoqi@0 | 15 | * You should have received a copy of the GNU General Public License version |
aoqi@0 | 16 | * 2 along with this work; if not, write to the Free Software Foundation, |
aoqi@0 | 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
aoqi@0 | 18 | * |
aoqi@0 | 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
aoqi@0 | 20 | * or visit www.oracle.com if you need additional information or have any |
aoqi@0 | 21 | * questions. |
aoqi@0 | 22 | * |
aoqi@0 | 23 | */ |
aoqi@0 | 24 | #include "libproc_impl.h" |
aoqi@0 | 25 | |
aoqi@0 | 26 | static const char* alt_root = NULL; |
aoqi@0 | 27 | static int alt_root_len = -1; |
aoqi@0 | 28 | |
aoqi@0 | 29 | #define SA_ALTROOT "SA_ALTROOT" |
aoqi@0 | 30 | |
aoqi@0 | 31 | off_t ltell(int fd) { |
aoqi@0 | 32 | return lseek(fd, 0, SEEK_CUR); |
aoqi@0 | 33 | } |
aoqi@0 | 34 | |
aoqi@0 | 35 | static void init_alt_root() { |
aoqi@0 | 36 | if (alt_root_len == -1) { |
aoqi@0 | 37 | alt_root = getenv(SA_ALTROOT); |
aoqi@0 | 38 | if (alt_root) { |
aoqi@0 | 39 | alt_root_len = strlen(alt_root); |
aoqi@0 | 40 | } else { |
aoqi@0 | 41 | alt_root_len = 0; |
aoqi@0 | 42 | } |
aoqi@0 | 43 | } |
aoqi@0 | 44 | } |
aoqi@0 | 45 | |
aoqi@0 | 46 | int pathmap_open(const char* name) { |
aoqi@0 | 47 | int fd; |
aoqi@0 | 48 | char alt_path[PATH_MAX + 1]; |
aoqi@0 | 49 | |
aoqi@0 | 50 | init_alt_root(); |
aoqi@0 | 51 | |
aoqi@0 | 52 | if (alt_root_len > 0) { |
aoqi@0 | 53 | strcpy(alt_path, alt_root); |
aoqi@0 | 54 | strcat(alt_path, name); |
aoqi@0 | 55 | fd = open(alt_path, O_RDONLY); |
aoqi@0 | 56 | if (fd >= 0) { |
aoqi@0 | 57 | print_debug("path %s substituted for %s\n", alt_path, name); |
aoqi@0 | 58 | return fd; |
aoqi@0 | 59 | } |
aoqi@0 | 60 | |
aoqi@0 | 61 | if (strrchr(name, '/')) { |
aoqi@0 | 62 | strcpy(alt_path, alt_root); |
aoqi@0 | 63 | strcat(alt_path, strrchr(name, '/')); |
aoqi@0 | 64 | fd = open(alt_path, O_RDONLY); |
aoqi@0 | 65 | if (fd >= 0) { |
aoqi@0 | 66 | print_debug("path %s substituted for %s\n", alt_path, name); |
aoqi@0 | 67 | return fd; |
aoqi@0 | 68 | } |
aoqi@0 | 69 | } |
aoqi@0 | 70 | } else { |
aoqi@0 | 71 | fd = open(name, O_RDONLY); |
aoqi@0 | 72 | if (fd >= 0) { |
aoqi@0 | 73 | return fd; |
aoqi@0 | 74 | } |
aoqi@0 | 75 | } |
aoqi@0 | 76 | return -1; |
aoqi@0 | 77 | } |
aoqi@0 | 78 | |
aoqi@0 | 79 | static bool _libsaproc_debug; |
aoqi@0 | 80 | |
aoqi@0 | 81 | void print_debug(const char* format,...) { |
aoqi@0 | 82 | if (_libsaproc_debug) { |
aoqi@0 | 83 | va_list alist; |
aoqi@0 | 84 | |
aoqi@0 | 85 | va_start(alist, format); |
aoqi@0 | 86 | fputs("libsaproc DEBUG: ", stderr); |
aoqi@0 | 87 | vfprintf(stderr, format, alist); |
aoqi@0 | 88 | va_end(alist); |
aoqi@0 | 89 | } |
aoqi@0 | 90 | } |
aoqi@0 | 91 | |
aoqi@0 | 92 | void print_error(const char* format,...) { |
aoqi@0 | 93 | va_list alist; |
aoqi@0 | 94 | va_start(alist, format); |
aoqi@0 | 95 | fputs("ERROR: ", stderr); |
aoqi@0 | 96 | vfprintf(stderr, format, alist); |
aoqi@0 | 97 | va_end(alist); |
aoqi@0 | 98 | } |
aoqi@0 | 99 | |
aoqi@0 | 100 | bool is_debug() { |
aoqi@0 | 101 | return _libsaproc_debug; |
aoqi@0 | 102 | } |
aoqi@0 | 103 | |
aoqi@0 | 104 | #ifdef __APPLE__ |
aoqi@0 | 105 | // get arch offset in file |
aoqi@0 | 106 | bool get_arch_off(int fd, cpu_type_t cputype, off_t *offset) { |
aoqi@0 | 107 | struct fat_header fatheader; |
aoqi@0 | 108 | struct fat_arch fatarch; |
aoqi@0 | 109 | off_t img_start = 0; |
aoqi@0 | 110 | |
aoqi@0 | 111 | off_t pos = ltell(fd); |
aoqi@0 | 112 | if (read(fd, (void *)&fatheader, sizeof(struct fat_header)) != sizeof(struct fat_header)) { |
aoqi@0 | 113 | return false; |
aoqi@0 | 114 | } |
aoqi@0 | 115 | if (fatheader.magic == FAT_CIGAM) { |
aoqi@0 | 116 | int i; |
aoqi@0 | 117 | for (i = 0; i < ntohl(fatheader.nfat_arch); i++) { |
aoqi@0 | 118 | if (read(fd, (void *)&fatarch, sizeof(struct fat_arch)) != sizeof(struct fat_arch)) { |
aoqi@0 | 119 | return false; |
aoqi@0 | 120 | } |
aoqi@0 | 121 | if (ntohl(fatarch.cputype) == cputype) { |
aoqi@0 | 122 | print_debug("fat offset=%x\n", ntohl(fatarch.offset)); |
aoqi@0 | 123 | img_start = ntohl(fatarch.offset); |
aoqi@0 | 124 | break; |
aoqi@0 | 125 | } |
aoqi@0 | 126 | } |
aoqi@0 | 127 | if (img_start == 0) { |
aoqi@0 | 128 | return false; |
aoqi@0 | 129 | } |
aoqi@0 | 130 | } |
aoqi@0 | 131 | lseek(fd, pos, SEEK_SET); |
aoqi@0 | 132 | *offset = img_start; |
aoqi@0 | 133 | return true; |
aoqi@0 | 134 | } |
aoqi@0 | 135 | |
aoqi@0 | 136 | bool is_macho_file(int fd) { |
aoqi@0 | 137 | mach_header_64 fhdr; |
aoqi@0 | 138 | off_t x86_64_off; |
aoqi@0 | 139 | |
aoqi@0 | 140 | if (fd < 0) { |
aoqi@0 | 141 | print_debug("Invalid file handle passed to is_macho_file\n"); |
aoqi@0 | 142 | return false; |
aoqi@0 | 143 | } |
aoqi@0 | 144 | |
aoqi@0 | 145 | off_t pos = ltell(fd); |
aoqi@0 | 146 | // check fat header |
aoqi@0 | 147 | if (!get_arch_off(fd, CPU_TYPE_X86_64, &x86_64_off)) { |
aoqi@0 | 148 | print_debug("failed to get fat header\n"); |
aoqi@0 | 149 | return false; |
aoqi@0 | 150 | } |
aoqi@0 | 151 | lseek(fd, x86_64_off, SEEK_SET); |
aoqi@0 | 152 | if (read(fd, (void *)&fhdr, sizeof(mach_header_64)) != sizeof(mach_header_64)) { |
aoqi@0 | 153 | return false; |
aoqi@0 | 154 | } |
aoqi@0 | 155 | lseek(fd, pos, SEEK_SET); // restore |
aoqi@0 | 156 | print_debug("fhdr.magic %x\n", fhdr.magic); |
aoqi@0 | 157 | return (fhdr.magic == MH_MAGIC_64 || fhdr.magic == MH_CIGAM_64); |
aoqi@0 | 158 | } |
aoqi@0 | 159 | |
aoqi@0 | 160 | #endif //__APPLE__ |
aoqi@0 | 161 | |
aoqi@0 | 162 | // initialize libproc |
aoqi@0 | 163 | bool init_libproc(bool debug) { |
aoqi@0 | 164 | _libsaproc_debug = debug; |
aoqi@0 | 165 | #ifndef __APPLE__ |
aoqi@0 | 166 | // initialize the thread_db library |
aoqi@0 | 167 | if (td_init() != TD_OK) { |
aoqi@0 | 168 | print_debug("libthread_db's td_init failed\n"); |
aoqi@0 | 169 | return false; |
aoqi@0 | 170 | } |
aoqi@0 | 171 | #endif // __APPLE__ |
aoqi@0 | 172 | return true; |
aoqi@0 | 173 | } |
aoqi@0 | 174 | |
aoqi@0 | 175 | void destroy_lib_info(struct ps_prochandle* ph) { |
aoqi@0 | 176 | lib_info* lib = ph->libs; |
aoqi@0 | 177 | while (lib) { |
aoqi@0 | 178 | lib_info* next = lib->next; |
aoqi@0 | 179 | if (lib->symtab) { |
aoqi@0 | 180 | destroy_symtab(lib->symtab); |
aoqi@0 | 181 | } |
aoqi@0 | 182 | free(lib); |
aoqi@0 | 183 | lib = next; |
aoqi@0 | 184 | } |
aoqi@0 | 185 | } |
aoqi@0 | 186 | |
aoqi@0 | 187 | void destroy_thread_info(struct ps_prochandle* ph) { |
aoqi@0 | 188 | sa_thread_info* thr = ph->threads; |
aoqi@0 | 189 | while (thr) { |
aoqi@0 | 190 | sa_thread_info* n = thr->next; |
aoqi@0 | 191 | free(thr); |
aoqi@0 | 192 | thr = n; |
aoqi@0 | 193 | } |
aoqi@0 | 194 | } |
aoqi@0 | 195 | |
aoqi@0 | 196 | // ps_prochandle cleanup |
aoqi@0 | 197 | void Prelease(struct ps_prochandle* ph) { |
aoqi@0 | 198 | // do the "derived class" clean-up first |
aoqi@0 | 199 | ph->ops->release(ph); |
aoqi@0 | 200 | destroy_lib_info(ph); |
aoqi@0 | 201 | destroy_thread_info(ph); |
aoqi@0 | 202 | free(ph); |
aoqi@0 | 203 | } |
aoqi@0 | 204 | |
aoqi@0 | 205 | lib_info* add_lib_info(struct ps_prochandle* ph, const char* libname, uintptr_t base) { |
aoqi@0 | 206 | return add_lib_info_fd(ph, libname, -1, base); |
aoqi@0 | 207 | } |
aoqi@0 | 208 | |
aoqi@0 | 209 | lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd, uintptr_t base) { |
aoqi@0 | 210 | lib_info* newlib; |
aoqi@0 | 211 | print_debug("add_lib_info_fd %s\n", libname); |
aoqi@0 | 212 | |
aoqi@0 | 213 | if ( (newlib = (lib_info*) calloc(1, sizeof(struct lib_info))) == NULL) { |
aoqi@0 | 214 | print_debug("can't allocate memory for lib_info\n"); |
aoqi@0 | 215 | return NULL; |
aoqi@0 | 216 | } |
aoqi@0 | 217 | |
aoqi@0 | 218 | strncpy(newlib->name, libname, sizeof(newlib->name)); |
aoqi@0 | 219 | newlib->base = base; |
aoqi@0 | 220 | |
aoqi@0 | 221 | if (fd == -1) { |
aoqi@0 | 222 | if ( (newlib->fd = pathmap_open(newlib->name)) < 0) { |
aoqi@0 | 223 | print_debug("can't open shared object %s\n", newlib->name); |
aoqi@0 | 224 | free(newlib); |
aoqi@0 | 225 | return NULL; |
aoqi@0 | 226 | } |
aoqi@0 | 227 | } else { |
aoqi@0 | 228 | newlib->fd = fd; |
aoqi@0 | 229 | } |
aoqi@0 | 230 | |
aoqi@0 | 231 | #ifdef __APPLE__ |
aoqi@0 | 232 | // check whether we have got an Macho file. |
aoqi@0 | 233 | if (is_macho_file(newlib->fd) == false) { |
aoqi@0 | 234 | close(newlib->fd); |
aoqi@0 | 235 | free(newlib); |
aoqi@0 | 236 | print_debug("not a mach-o file\n"); |
aoqi@0 | 237 | return NULL; |
aoqi@0 | 238 | } |
aoqi@0 | 239 | #else |
aoqi@0 | 240 | // check whether we have got an ELF file. /proc/<pid>/map |
aoqi@0 | 241 | // gives out all file mappings and not just shared objects |
aoqi@0 | 242 | if (is_elf_file(newlib->fd) == false) { |
aoqi@0 | 243 | close(newlib->fd); |
aoqi@0 | 244 | free(newlib); |
aoqi@0 | 245 | return NULL; |
aoqi@0 | 246 | } |
aoqi@0 | 247 | #endif // __APPLE__ |
aoqi@0 | 248 | |
aoqi@0 | 249 | newlib->symtab = build_symtab(newlib->fd); |
aoqi@0 | 250 | if (newlib->symtab == NULL) { |
aoqi@0 | 251 | print_debug("symbol table build failed for %s\n", newlib->name); |
aoqi@0 | 252 | } else { |
aoqi@0 | 253 | print_debug("built symbol table for %s\n", newlib->name); |
aoqi@0 | 254 | } |
aoqi@0 | 255 | |
aoqi@0 | 256 | // even if symbol table building fails, we add the lib_info. |
aoqi@0 | 257 | // This is because we may need to read from the ELF file or MachO file for core file |
aoqi@0 | 258 | // address read functionality. lookup_symbol checks for NULL symtab. |
aoqi@0 | 259 | if (ph->libs) { |
aoqi@0 | 260 | ph->lib_tail->next = newlib; |
aoqi@0 | 261 | ph->lib_tail = newlib; |
aoqi@0 | 262 | } else { |
aoqi@0 | 263 | ph->libs = ph->lib_tail = newlib; |
aoqi@0 | 264 | } |
aoqi@0 | 265 | ph->num_libs++; |
aoqi@0 | 266 | return newlib; |
aoqi@0 | 267 | } |
aoqi@0 | 268 | |
aoqi@0 | 269 | // lookup for a specific symbol |
aoqi@0 | 270 | uintptr_t lookup_symbol(struct ps_prochandle* ph, const char* object_name, |
aoqi@0 | 271 | const char* sym_name) { |
aoqi@0 | 272 | // ignore object_name. search in all libraries |
aoqi@0 | 273 | // FIXME: what should we do with object_name?? The library names are obtained |
aoqi@0 | 274 | // by parsing /proc/<pid>/maps, which may not be the same as object_name. |
aoqi@0 | 275 | // What we need is a utility to map object_name to real file name, something |
aoqi@0 | 276 | // dlopen() does by looking at LD_LIBRARY_PATH and /etc/ld.so.cache. For |
aoqi@0 | 277 | // now, we just ignore object_name and do a global search for the symbol. |
aoqi@0 | 278 | |
aoqi@0 | 279 | lib_info* lib = ph->libs; |
aoqi@0 | 280 | while (lib) { |
aoqi@0 | 281 | if (lib->symtab) { |
aoqi@0 | 282 | uintptr_t res = search_symbol(lib->symtab, lib->base, sym_name, NULL); |
aoqi@0 | 283 | if (res) return res; |
aoqi@0 | 284 | } |
aoqi@0 | 285 | lib = lib->next; |
aoqi@0 | 286 | } |
aoqi@0 | 287 | |
aoqi@0 | 288 | print_debug("lookup failed for symbol '%s' in obj '%s'\n", |
aoqi@0 | 289 | sym_name, object_name); |
aoqi@0 | 290 | return (uintptr_t) NULL; |
aoqi@0 | 291 | } |
aoqi@0 | 292 | |
aoqi@0 | 293 | const char* symbol_for_pc(struct ps_prochandle* ph, uintptr_t addr, uintptr_t* poffset) { |
aoqi@0 | 294 | const char* res = NULL; |
aoqi@0 | 295 | lib_info* lib = ph->libs; |
aoqi@0 | 296 | while (lib) { |
aoqi@0 | 297 | if (lib->symtab && addr >= lib->base) { |
aoqi@0 | 298 | res = nearest_symbol(lib->symtab, addr - lib->base, poffset); |
aoqi@0 | 299 | if (res) return res; |
aoqi@0 | 300 | } |
aoqi@0 | 301 | lib = lib->next; |
aoqi@0 | 302 | } |
aoqi@0 | 303 | return NULL; |
aoqi@0 | 304 | } |
aoqi@0 | 305 | |
aoqi@0 | 306 | // add a thread to ps_prochandle |
aoqi@0 | 307 | sa_thread_info* add_thread_info(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id) { |
aoqi@0 | 308 | sa_thread_info* newthr; |
aoqi@0 | 309 | if ( (newthr = (sa_thread_info*) calloc(1, sizeof(sa_thread_info))) == NULL) { |
aoqi@0 | 310 | print_debug("can't allocate memory for thread_info\n"); |
aoqi@0 | 311 | return NULL; |
aoqi@0 | 312 | } |
aoqi@0 | 313 | |
aoqi@0 | 314 | // initialize thread info |
aoqi@0 | 315 | newthr->pthread_id = pthread_id; |
aoqi@0 | 316 | newthr->lwp_id = lwp_id; |
aoqi@0 | 317 | |
aoqi@0 | 318 | // add new thread to the list |
aoqi@0 | 319 | newthr->next = ph->threads; |
aoqi@0 | 320 | ph->threads = newthr; |
aoqi@0 | 321 | ph->num_threads++; |
aoqi@0 | 322 | return newthr; |
aoqi@0 | 323 | } |
aoqi@0 | 324 | |
aoqi@0 | 325 | #ifndef __APPLE__ |
aoqi@0 | 326 | // struct used for client data from thread_db callback |
aoqi@0 | 327 | struct thread_db_client_data { |
aoqi@0 | 328 | struct ps_prochandle* ph; |
aoqi@0 | 329 | thread_info_callback callback; |
aoqi@0 | 330 | }; |
aoqi@0 | 331 | |
aoqi@0 | 332 | // callback function for libthread_db |
aoqi@0 | 333 | static int thread_db_callback(const td_thrhandle_t *th_p, void *data) { |
aoqi@0 | 334 | struct thread_db_client_data* ptr = (struct thread_db_client_data*) data; |
aoqi@0 | 335 | td_thrinfo_t ti; |
aoqi@0 | 336 | td_err_e err; |
aoqi@0 | 337 | |
aoqi@0 | 338 | memset(&ti, 0, sizeof(ti)); |
aoqi@0 | 339 | err = td_thr_get_info(th_p, &ti); |
aoqi@0 | 340 | if (err != TD_OK) { |
aoqi@0 | 341 | print_debug("libthread_db : td_thr_get_info failed, can't get thread info\n"); |
aoqi@0 | 342 | return err; |
aoqi@0 | 343 | } |
aoqi@0 | 344 | |
aoqi@0 | 345 | print_debug("thread_db : pthread %d (lwp %d)\n", ti.ti_tid, ti.ti_lid); |
aoqi@0 | 346 | |
aoqi@0 | 347 | if (ptr->callback(ptr->ph, (pthread_t)ti.ti_tid, ti.ti_lid) != true) |
aoqi@0 | 348 | return TD_ERR; |
aoqi@0 | 349 | |
aoqi@0 | 350 | return TD_OK; |
aoqi@0 | 351 | } |
aoqi@0 | 352 | |
aoqi@0 | 353 | // read thread_info using libthread_db |
aoqi@0 | 354 | bool read_thread_info(struct ps_prochandle* ph, thread_info_callback cb) { |
aoqi@0 | 355 | struct thread_db_client_data mydata; |
aoqi@0 | 356 | td_thragent_t* thread_agent = NULL; |
aoqi@0 | 357 | if (td_ta_new(ph, &thread_agent) != TD_OK) { |
aoqi@0 | 358 | print_debug("can't create libthread_db agent\n"); |
aoqi@0 | 359 | return false; |
aoqi@0 | 360 | } |
aoqi@0 | 361 | |
aoqi@0 | 362 | mydata.ph = ph; |
aoqi@0 | 363 | mydata.callback = cb; |
aoqi@0 | 364 | |
aoqi@0 | 365 | // we use libthread_db iterator to iterate thru list of threads. |
aoqi@0 | 366 | if (td_ta_thr_iter(thread_agent, thread_db_callback, &mydata, |
aoqi@0 | 367 | TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY, |
aoqi@0 | 368 | TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS) != TD_OK) { |
aoqi@0 | 369 | td_ta_delete(thread_agent); |
aoqi@0 | 370 | return false; |
aoqi@0 | 371 | } |
aoqi@0 | 372 | |
aoqi@0 | 373 | // delete thread agent |
aoqi@0 | 374 | td_ta_delete(thread_agent); |
aoqi@0 | 375 | return true; |
aoqi@0 | 376 | } |
aoqi@0 | 377 | |
aoqi@0 | 378 | #endif // __APPLE__ |
aoqi@0 | 379 | |
aoqi@0 | 380 | // get number of threads |
aoqi@0 | 381 | int get_num_threads(struct ps_prochandle* ph) { |
aoqi@0 | 382 | return ph->num_threads; |
aoqi@0 | 383 | } |
aoqi@0 | 384 | |
aoqi@0 | 385 | // get lwp_id of n'th thread |
aoqi@0 | 386 | lwpid_t get_lwp_id(struct ps_prochandle* ph, int index) { |
aoqi@0 | 387 | int count = 0; |
aoqi@0 | 388 | sa_thread_info* thr = ph->threads; |
aoqi@0 | 389 | while (thr) { |
aoqi@0 | 390 | if (count == index) { |
aoqi@0 | 391 | return thr->lwp_id; |
aoqi@0 | 392 | } |
aoqi@0 | 393 | count++; |
aoqi@0 | 394 | thr = thr->next; |
aoqi@0 | 395 | } |
aoqi@0 | 396 | return 0; |
aoqi@0 | 397 | } |
aoqi@0 | 398 | |
aoqi@0 | 399 | #ifdef __APPLE__ |
aoqi@0 | 400 | // set lwp_id of n'th thread |
aoqi@0 | 401 | bool set_lwp_id(struct ps_prochandle* ph, int index, lwpid_t lwpid) { |
aoqi@0 | 402 | int count = 0; |
aoqi@0 | 403 | sa_thread_info* thr = ph->threads; |
aoqi@0 | 404 | while (thr) { |
aoqi@0 | 405 | if (count == index) { |
aoqi@0 | 406 | thr->lwp_id = lwpid; |
aoqi@0 | 407 | return true; |
aoqi@0 | 408 | } |
aoqi@0 | 409 | count++; |
aoqi@0 | 410 | thr = thr->next; |
aoqi@0 | 411 | } |
aoqi@0 | 412 | return false; |
aoqi@0 | 413 | } |
aoqi@0 | 414 | |
aoqi@0 | 415 | // get regs of n-th thread, only used in fillThreads the first time called |
aoqi@0 | 416 | bool get_nth_lwp_regs(struct ps_prochandle* ph, int index, struct reg* regs) { |
aoqi@0 | 417 | int count = 0; |
aoqi@0 | 418 | sa_thread_info* thr = ph->threads; |
aoqi@0 | 419 | while (thr) { |
aoqi@0 | 420 | if (count == index) { |
aoqi@0 | 421 | break; |
aoqi@0 | 422 | } |
aoqi@0 | 423 | count++; |
aoqi@0 | 424 | thr = thr->next; |
aoqi@0 | 425 | } |
aoqi@0 | 426 | if (thr != NULL) { |
aoqi@0 | 427 | memcpy(regs, &thr->regs, sizeof(struct reg)); |
aoqi@0 | 428 | return true; |
aoqi@0 | 429 | } |
aoqi@0 | 430 | return false; |
aoqi@0 | 431 | } |
aoqi@0 | 432 | |
aoqi@0 | 433 | #endif // __APPLE__ |
aoqi@0 | 434 | |
aoqi@0 | 435 | // get regs for a given lwp |
aoqi@0 | 436 | bool get_lwp_regs(struct ps_prochandle* ph, lwpid_t lwp_id, struct reg* regs) { |
aoqi@0 | 437 | return ph->ops->get_lwp_regs(ph, lwp_id, regs); |
aoqi@0 | 438 | } |
aoqi@0 | 439 | |
aoqi@0 | 440 | // get number of shared objects |
aoqi@0 | 441 | int get_num_libs(struct ps_prochandle* ph) { |
aoqi@0 | 442 | return ph->num_libs; |
aoqi@0 | 443 | } |
aoqi@0 | 444 | |
aoqi@0 | 445 | // get name of n'th solib |
aoqi@0 | 446 | const char* get_lib_name(struct ps_prochandle* ph, int index) { |
aoqi@0 | 447 | int count = 0; |
aoqi@0 | 448 | lib_info* lib = ph->libs; |
aoqi@0 | 449 | while (lib) { |
aoqi@0 | 450 | if (count == index) { |
aoqi@0 | 451 | return lib->name; |
aoqi@0 | 452 | } |
aoqi@0 | 453 | count++; |
aoqi@0 | 454 | lib = lib->next; |
aoqi@0 | 455 | } |
aoqi@0 | 456 | return NULL; |
aoqi@0 | 457 | } |
aoqi@0 | 458 | |
aoqi@0 | 459 | // get base address of a lib |
aoqi@0 | 460 | uintptr_t get_lib_base(struct ps_prochandle* ph, int index) { |
aoqi@0 | 461 | int count = 0; |
aoqi@0 | 462 | lib_info* lib = ph->libs; |
aoqi@0 | 463 | while (lib) { |
aoqi@0 | 464 | if (count == index) { |
aoqi@0 | 465 | return lib->base; |
aoqi@0 | 466 | } |
aoqi@0 | 467 | count++; |
aoqi@0 | 468 | lib = lib->next; |
aoqi@0 | 469 | } |
aoqi@0 | 470 | return (uintptr_t)NULL; |
aoqi@0 | 471 | } |
aoqi@0 | 472 | |
aoqi@0 | 473 | bool find_lib(struct ps_prochandle* ph, const char *lib_name) { |
aoqi@0 | 474 | lib_info *p = ph->libs; |
aoqi@0 | 475 | while (p) { |
aoqi@0 | 476 | if (strcmp(p->name, lib_name) == 0) { |
aoqi@0 | 477 | return true; |
aoqi@0 | 478 | } |
aoqi@0 | 479 | p = p->next; |
aoqi@0 | 480 | } |
aoqi@0 | 481 | return false; |
aoqi@0 | 482 | } |
aoqi@0 | 483 | |
aoqi@0 | 484 | //-------------------------------------------------------------------------- |
aoqi@0 | 485 | // proc service functions |
aoqi@0 | 486 | |
aoqi@0 | 487 | // ps_pglobal_lookup() looks up the symbol sym_name in the symbol table |
aoqi@0 | 488 | // of the load object object_name in the target process identified by ph. |
aoqi@0 | 489 | // It returns the symbol's value as an address in the target process in |
aoqi@0 | 490 | // *sym_addr. |
aoqi@0 | 491 | |
aoqi@0 | 492 | ps_err_e ps_pglobal_lookup(struct ps_prochandle *ph, const char *object_name, |
aoqi@0 | 493 | const char *sym_name, psaddr_t *sym_addr) { |
aoqi@0 | 494 | *sym_addr = (psaddr_t) lookup_symbol(ph, object_name, sym_name); |
aoqi@0 | 495 | return (*sym_addr ? PS_OK : PS_NOSYM); |
aoqi@0 | 496 | } |
aoqi@0 | 497 | |
aoqi@0 | 498 | // read "size" bytes info "buf" from address "addr" |
aoqi@0 | 499 | ps_err_e ps_pread(struct ps_prochandle *ph, psaddr_t addr, |
aoqi@0 | 500 | void *buf, size_t size) { |
aoqi@0 | 501 | return ph->ops->p_pread(ph, (uintptr_t) addr, buf, size)? PS_OK: PS_ERR; |
aoqi@0 | 502 | } |
aoqi@0 | 503 | |
aoqi@0 | 504 | // write "size" bytes of data to debuggee at address "addr" |
aoqi@0 | 505 | ps_err_e ps_pwrite(struct ps_prochandle *ph, psaddr_t addr, |
aoqi@0 | 506 | const void *buf, size_t size) { |
aoqi@0 | 507 | return ph->ops->p_pwrite(ph, (uintptr_t)addr, buf, size)? PS_OK: PS_ERR; |
aoqi@0 | 508 | } |
aoqi@0 | 509 | |
aoqi@0 | 510 | // fill in ptrace_lwpinfo for lid |
aoqi@0 | 511 | ps_err_e ps_linfo(struct ps_prochandle *ph, lwpid_t lwp_id, void *linfo) { |
aoqi@0 | 512 | return ph->ops->get_lwp_info(ph, lwp_id, linfo)? PS_OK: PS_ERR; |
aoqi@0 | 513 | } |
aoqi@0 | 514 | |
aoqi@0 | 515 | // needed for when libthread_db is compiled with TD_DEBUG defined |
aoqi@0 | 516 | void |
aoqi@0 | 517 | ps_plog (const char *format, ...) |
aoqi@0 | 518 | { |
aoqi@0 | 519 | va_list alist; |
aoqi@0 | 520 | |
aoqi@0 | 521 | va_start(alist, format); |
aoqi@0 | 522 | vfprintf(stderr, format, alist); |
aoqi@0 | 523 | va_end(alist); |
aoqi@0 | 524 | } |
aoqi@0 | 525 | |
aoqi@0 | 526 | #ifndef __APPLE__ |
aoqi@0 | 527 | // ------------------------------------------------------------------------ |
aoqi@0 | 528 | // Functions below this point are not yet implemented. They are here only |
aoqi@0 | 529 | // to make the linker happy. |
aoqi@0 | 530 | |
aoqi@0 | 531 | ps_err_e ps_lsetfpregs(struct ps_prochandle *ph, lwpid_t lid, const prfpregset_t *fpregs) { |
aoqi@0 | 532 | print_debug("ps_lsetfpregs not implemented\n"); |
aoqi@0 | 533 | return PS_OK; |
aoqi@0 | 534 | } |
aoqi@0 | 535 | |
aoqi@0 | 536 | ps_err_e ps_lsetregs(struct ps_prochandle *ph, lwpid_t lid, const prgregset_t gregset) { |
aoqi@0 | 537 | print_debug("ps_lsetregs not implemented\n"); |
aoqi@0 | 538 | return PS_OK; |
aoqi@0 | 539 | } |
aoqi@0 | 540 | |
aoqi@0 | 541 | ps_err_e ps_lgetfpregs(struct ps_prochandle *ph, lwpid_t lid, prfpregset_t *fpregs) { |
aoqi@0 | 542 | print_debug("ps_lgetfpregs not implemented\n"); |
aoqi@0 | 543 | return PS_OK; |
aoqi@0 | 544 | } |
aoqi@0 | 545 | |
aoqi@0 | 546 | ps_err_e ps_lgetregs(struct ps_prochandle *ph, lwpid_t lid, prgregset_t gregset) { |
aoqi@0 | 547 | print_debug("ps_lgetfpregs not implemented\n"); |
aoqi@0 | 548 | return PS_OK; |
aoqi@0 | 549 | } |
aoqi@0 | 550 | |
aoqi@0 | 551 | ps_err_e ps_lstop(struct ps_prochandle *ph, lwpid_t lid) { |
aoqi@0 | 552 | print_debug("ps_lstop not implemented\n"); |
aoqi@0 | 553 | return PS_OK; |
aoqi@0 | 554 | } |
aoqi@0 | 555 | |
aoqi@0 | 556 | ps_err_e ps_pcontinue(struct ps_prochandle *ph) { |
aoqi@0 | 557 | print_debug("ps_pcontinue not implemented\n"); |
aoqi@0 | 558 | return PS_OK; |
aoqi@0 | 559 | } |
aoqi@0 | 560 | #endif // __APPLE__ |