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