comparison agent/src/os/bsd/libproc_impl.c @ 8750:39432a1cefdd

8003348: SA can not read core file on OS Summary: Macosx uses Mach-O file format for binary files, not ELF format. Currently SA works on core files on other platforms, t his change enables SA work on core file generated on Darwin. Reviewed-by: sla, sspitsyn Contributed-by: yumin.qi@oracle.com
author minqi
date Thu, 14 Mar 2013 00:33:08 -0700
parents 2394a89e89f4
children
comparison
equal deleted inserted replaced
8719:c8b31b461e1a 8750:39432a1cefdd
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 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 20 * or visit www.oracle.com if you need additional information or have any
21 * questions. 21 * questions.
22 * 22 *
23 */ 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" 24 #include "libproc_impl.h"
31 25
32 static const char* alt_root = NULL; 26 static const char* alt_root = NULL;
33 static int alt_root_len = -1; 27 static int alt_root_len = -1;
34 28
35 #define SA_ALTROOT "SA_ALTROOT" 29 #define SA_ALTROOT "SA_ALTROOT"
36 30
31 off_t ltell(int fd) {
32 return lseek(fd, 0, SEEK_CUR);
33 }
34
37 static void init_alt_root() { 35 static void init_alt_root() {
38 if (alt_root_len == -1) { 36 if (alt_root_len == -1) {
39 alt_root = getenv(SA_ALTROOT); 37 alt_root = getenv(SA_ALTROOT);
40 if (alt_root) { 38 if (alt_root) {
41 alt_root_len = strlen(alt_root); 39 alt_root_len = strlen(alt_root);
42 } else { 40 } else {
43 alt_root_len = 0; 41 alt_root_len = 0;
44 } 42 }
45 } 43 }
46 } 44 }
47 45
48 int pathmap_open(const char* name) { 46 int pathmap_open(const char* name) {
49 int fd; 47 int fd;
50 char alt_path[PATH_MAX + 1]; 48 char alt_path[PATH_MAX + 1];
51 49
52 init_alt_root(); 50 init_alt_root();
53 fd = open(name, O_RDONLY); 51
54 if (fd >= 0) { 52 if (alt_root_len > 0) {
53 strcpy(alt_path, alt_root);
54 strcat(alt_path, name);
55 fd = open(alt_path, O_RDONLY);
56 if (fd >= 0) {
57 print_debug("path %s substituted for %s\n", alt_path, name);
55 return fd; 58 return fd;
56 } 59 }
57 60
58 if (alt_root_len > 0) { 61 if (strrchr(name, '/')) {
59 strcpy(alt_path, alt_root); 62 strcpy(alt_path, alt_root);
60 strcat(alt_path, name); 63 strcat(alt_path, strrchr(name, '/'));
61 fd = open(alt_path, O_RDONLY); 64 fd = open(alt_path, O_RDONLY);
62 if (fd >= 0) { 65 if (fd >= 0) {
63 print_debug("path %s substituted for %s\n", alt_path, name); 66 print_debug("path %s substituted for %s\n", alt_path, name);
64 return fd; 67 return fd;
65 } 68 }
66 69 }
67 if (strrchr(name, '/')) { 70 } else {
68 strcpy(alt_path, alt_root); 71 fd = open(name, O_RDONLY);
69 strcat(alt_path, strrchr(name, '/')); 72 if (fd >= 0) {
70 fd = open(alt_path, O_RDONLY); 73 return fd;
71 if (fd >= 0) { 74 }
72 print_debug("path %s substituted for %s\n", alt_path, name); 75 }
73 return fd; 76 return -1;
74 }
75 }
76 }
77
78 return -1;
79 } 77 }
80 78
81 static bool _libsaproc_debug; 79 static bool _libsaproc_debug;
82 80
83 void print_debug(const char* format,...) { 81 void print_debug(const char* format,...) {
84 if (_libsaproc_debug) { 82 if (_libsaproc_debug) {
85 va_list alist; 83 va_list alist;
86 84
87 va_start(alist, format); 85 va_start(alist, format);
88 fputs("libsaproc DEBUG: ", stderr); 86 fputs("libsaproc DEBUG: ", stderr);
89 vfprintf(stderr, format, alist); 87 vfprintf(stderr, format, alist);
90 va_end(alist); 88 va_end(alist);
91 } 89 }
92 } 90 }
93 91
94 void print_error(const char* format,...) { 92 void print_error(const char* format,...) {
95 va_list alist; 93 va_list alist;
96 va_start(alist, format); 94 va_start(alist, format);
98 vfprintf(stderr, format, alist); 96 vfprintf(stderr, format, alist);
99 va_end(alist); 97 va_end(alist);
100 } 98 }
101 99
102 bool is_debug() { 100 bool is_debug() {
103 return _libsaproc_debug; 101 return _libsaproc_debug;
104 } 102 }
103
104 #ifdef __APPLE__
105 // get arch offset in file
106 bool get_arch_off(int fd, cpu_type_t cputype, off_t *offset) {
107 struct fat_header fatheader;
108 struct fat_arch fatarch;
109 off_t img_start = 0;
110
111 off_t pos = ltell(fd);
112 if (read(fd, (void *)&fatheader, sizeof(struct fat_header)) != sizeof(struct fat_header)) {
113 return false;
114 }
115 if (fatheader.magic == FAT_CIGAM) {
116 int i;
117 for (i = 0; i < ntohl(fatheader.nfat_arch); i++) {
118 if (read(fd, (void *)&fatarch, sizeof(struct fat_arch)) != sizeof(struct fat_arch)) {
119 return false;
120 }
121 if (ntohl(fatarch.cputype) == cputype) {
122 print_debug("fat offset=%x\n", ntohl(fatarch.offset));
123 img_start = ntohl(fatarch.offset);
124 break;
125 }
126 }
127 if (img_start == 0) {
128 return false;
129 }
130 }
131 lseek(fd, pos, SEEK_SET);
132 *offset = img_start;
133 return true;
134 }
135
136 bool is_macho_file(int fd) {
137 mach_header_64 fhdr;
138 off_t x86_64_off;
139
140 if (fd < 0) {
141 print_debug("Invalid file handle passed to is_macho_file\n");
142 return false;
143 }
144
145 off_t pos = ltell(fd);
146 // check fat header
147 if (!get_arch_off(fd, CPU_TYPE_X86_64, &x86_64_off)) {
148 print_debug("failed to get fat header\n");
149 return false;
150 }
151 lseek(fd, x86_64_off, SEEK_SET);
152 if (read(fd, (void *)&fhdr, sizeof(mach_header_64)) != sizeof(mach_header_64)) {
153 return false;
154 }
155 lseek(fd, pos, SEEK_SET); // restore
156 print_debug("fhdr.magic %x\n", fhdr.magic);
157 return (fhdr.magic == MH_MAGIC_64 || fhdr.magic == MH_CIGAM_64);
158 }
159
160 #endif //__APPLE__
105 161
106 // initialize libproc 162 // initialize libproc
107 bool init_libproc(bool debug) { 163 bool init_libproc(bool debug) {
108 // init debug mode
109 _libsaproc_debug = debug; 164 _libsaproc_debug = debug;
110 165 #ifndef __APPLE__
111 // initialize the thread_db library 166 // initialize the thread_db library
112 if (td_init() != TD_OK) { 167 if (td_init() != TD_OK) {
113 print_debug("libthread_db's td_init failed\n"); 168 print_debug("libthread_db's td_init failed\n");
114 return false; 169 return false;
115 } 170 }
116 171 #endif // __APPLE__
117 return true; 172 return true;
118 } 173 }
119 174
120 static void destroy_lib_info(struct ps_prochandle* ph) { 175 void destroy_lib_info(struct ps_prochandle* ph) {
121 lib_info* lib = ph->libs; 176 lib_info* lib = ph->libs;
122 while (lib) { 177 while (lib) {
123 lib_info *next = lib->next; 178 lib_info* next = lib->next;
124 if (lib->symtab) { 179 if (lib->symtab) {
125 destroy_symtab(lib->symtab); 180 destroy_symtab(lib->symtab);
126 } 181 }
127 free(lib); 182 free(lib);
128 lib = next; 183 lib = next;
129 } 184 }
130 } 185 }
131 186
132 static void destroy_thread_info(struct ps_prochandle* ph) { 187 void destroy_thread_info(struct ps_prochandle* ph) {
133 thread_info* thr = ph->threads; 188 sa_thread_info* thr = ph->threads;
134 while (thr) { 189 while (thr) {
135 thread_info *next = thr->next; 190 sa_thread_info* n = thr->next;
136 free(thr); 191 free(thr);
137 thr = next; 192 thr = n;
138 } 193 }
139 } 194 }
140
141 // ps_prochandle cleanup
142 195
143 // ps_prochandle cleanup 196 // ps_prochandle cleanup
144 void Prelease(struct ps_prochandle* ph) { 197 void Prelease(struct ps_prochandle* ph) {
145 // do the "derived class" clean-up first 198 // do the "derived class" clean-up first
146 ph->ops->release(ph); 199 ph->ops->release(ph);
147 destroy_lib_info(ph); 200 destroy_lib_info(ph);
148 destroy_thread_info(ph); 201 destroy_thread_info(ph);
149 free(ph); 202 free(ph);
150 } 203 }
151 204
152 lib_info* add_lib_info(struct ps_prochandle* ph, const char* libname, uintptr_t base) { 205 lib_info* add_lib_info(struct ps_prochandle* ph, const char* libname, uintptr_t base) {
153 return add_lib_info_fd(ph, libname, -1, base); 206 return add_lib_info_fd(ph, libname, -1, base);
154 } 207 }
155 208
156 lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd, uintptr_t base) { 209 lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd, uintptr_t base) {
157 lib_info* newlib; 210 lib_info* newlib;
158 211 print_debug("add_lib_info_fd %s\n", libname);
159 if ( (newlib = (lib_info*) calloc(1, sizeof(struct lib_info))) == NULL) { 212
160 print_debug("can't allocate memory for lib_info\n"); 213 if ( (newlib = (lib_info*) calloc(1, sizeof(struct lib_info))) == NULL) {
161 return NULL; 214 print_debug("can't allocate memory for lib_info\n");
162 } 215 return NULL;
163 216 }
164 strncpy(newlib->name, libname, sizeof(newlib->name)); 217
165 newlib->base = base; 218 strncpy(newlib->name, libname, sizeof(newlib->name));
166 219 newlib->base = base;
167 if (fd == -1) { 220
168 if ( (newlib->fd = pathmap_open(newlib->name)) < 0) { 221 if (fd == -1) {
169 print_debug("can't open shared object %s\n", newlib->name); 222 if ( (newlib->fd = pathmap_open(newlib->name)) < 0) {
170 free(newlib); 223 print_debug("can't open shared object %s\n", newlib->name);
171 return NULL;
172 }
173 } else {
174 newlib->fd = fd;
175 }
176
177 // check whether we have got an ELF file. /proc/<pid>/map
178 // gives out all file mappings and not just shared objects
179 if (is_elf_file(newlib->fd) == false) {
180 close(newlib->fd);
181 free(newlib); 224 free(newlib);
182 return NULL; 225 return NULL;
183 } 226 }
184 227 } else {
185 newlib->symtab = build_symtab(newlib->fd); 228 newlib->fd = fd;
186 if (newlib->symtab == NULL) { 229 }
187 print_debug("symbol table build failed for %s\n", newlib->name); 230
188 } 231 #ifdef __APPLE__
189 else { 232 // check whether we have got an Macho file.
190 print_debug("built symbol table for %s\n", newlib->name); 233 if (is_macho_file(newlib->fd) == false) {
191 } 234 close(newlib->fd);
192 235 free(newlib);
193 // even if symbol table building fails, we add the lib_info. 236 print_debug("not a mach-o file\n");
194 // This is because we may need to read from the ELF file for core file 237 return NULL;
195 // address read functionality. lookup_symbol checks for NULL symtab. 238 }
196 if (ph->libs) { 239 #else
197 ph->lib_tail->next = newlib; 240 // check whether we have got an ELF file. /proc/<pid>/map
198 ph->lib_tail = newlib; 241 // gives out all file mappings and not just shared objects
199 } else { 242 if (is_elf_file(newlib->fd) == false) {
200 ph->libs = ph->lib_tail = newlib; 243 close(newlib->fd);
201 } 244 free(newlib);
202 ph->num_libs++; 245 return NULL;
203 246 }
204 return newlib; 247 #endif // __APPLE__
248
249 newlib->symtab = build_symtab(newlib->fd);
250 if (newlib->symtab == NULL) {
251 print_debug("symbol table build failed for %s\n", newlib->name);
252 } else {
253 print_debug("built symbol table for %s\n", newlib->name);
254 }
255
256 // even if symbol table building fails, we add the lib_info.
257 // This is because we may need to read from the ELF file or MachO file for core file
258 // address read functionality. lookup_symbol checks for NULL symtab.
259 if (ph->libs) {
260 ph->lib_tail->next = newlib;
261 ph->lib_tail = newlib;
262 } else {
263 ph->libs = ph->lib_tail = newlib;
264 }
265 ph->num_libs++;
266 return newlib;
205 } 267 }
206 268
207 // lookup for a specific symbol 269 // lookup for a specific symbol
208 uintptr_t lookup_symbol(struct ps_prochandle* ph, const char* object_name, 270 uintptr_t lookup_symbol(struct ps_prochandle* ph, const char* object_name,
209 const char* sym_name) { 271 const char* sym_name) {
210 // ignore object_name. search in all libraries 272 // ignore object_name. search in all libraries
211 // FIXME: what should we do with object_name?? The library names are obtained 273 // 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. 274 // 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 275 // 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 276 // 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. 277 // now, we just ignore object_name and do a global search for the symbol.
216 278
217 lib_info* lib = ph->libs; 279 lib_info* lib = ph->libs;
218 while (lib) { 280 while (lib) {
219 if (lib->symtab) { 281 if (lib->symtab) {
220 uintptr_t res = search_symbol(lib->symtab, lib->base, sym_name, NULL); 282 uintptr_t res = search_symbol(lib->symtab, lib->base, sym_name, NULL);
221 if (res) return res; 283 if (res) return res;
222 } 284 }
223 lib = lib->next; 285 lib = lib->next;
224 } 286 }
225 287
226 print_debug("lookup failed for symbol '%s' in obj '%s'\n", 288 print_debug("lookup failed for symbol '%s' in obj '%s'\n",
227 sym_name, object_name); 289 sym_name, object_name);
228 return (uintptr_t) NULL; 290 return (uintptr_t) NULL;
229 } 291 }
230
231 292
232 const char* symbol_for_pc(struct ps_prochandle* ph, uintptr_t addr, uintptr_t* poffset) { 293 const char* symbol_for_pc(struct ps_prochandle* ph, uintptr_t addr, uintptr_t* poffset) {
233 const char* res = NULL; 294 const char* res = NULL;
234 lib_info* lib = ph->libs; 295 lib_info* lib = ph->libs;
235 while (lib) { 296 while (lib) {
236 if (lib->symtab && addr >= lib->base) { 297 if (lib->symtab && addr >= lib->base) {
237 res = nearest_symbol(lib->symtab, addr - lib->base, poffset); 298 res = nearest_symbol(lib->symtab, addr - lib->base, poffset);
238 if (res) return res; 299 if (res) return res;
239 } 300 }
240 lib = lib->next; 301 lib = lib->next;
241 } 302 }
242 return NULL; 303 return NULL;
243 } 304 }
244 305
245 // add a thread to ps_prochandle 306 // add a thread to ps_prochandle
246 thread_info* add_thread_info(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id) { 307 sa_thread_info* add_thread_info(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id) {
247 thread_info* newthr; 308 sa_thread_info* newthr;
248 if ( (newthr = (thread_info*) calloc(1, sizeof(thread_info))) == NULL) { 309 if ( (newthr = (sa_thread_info*) calloc(1, sizeof(sa_thread_info))) == NULL) {
249 print_debug("can't allocate memory for thread_info\n"); 310 print_debug("can't allocate memory for thread_info\n");
250 return NULL; 311 return NULL;
251 } 312 }
252 313
253 // initialize thread info 314 // initialize thread info
254 newthr->pthread_id = pthread_id; 315 newthr->pthread_id = pthread_id;
255 newthr->lwp_id = lwp_id; 316 newthr->lwp_id = lwp_id;
256 317
257 // add new thread to the list 318 // add new thread to the list
258 newthr->next = ph->threads; 319 newthr->next = ph->threads;
259 ph->threads = newthr; 320 ph->threads = newthr;
260 ph->num_threads++; 321 ph->num_threads++;
261 return newthr; 322 return newthr;
262 } 323 }
263 324
264 325 #ifndef __APPLE__
265 // struct used for client data from thread_db callback 326 // struct used for client data from thread_db callback
266 struct thread_db_client_data { 327 struct thread_db_client_data {
267 struct ps_prochandle* ph; 328 struct ps_prochandle* ph;
268 thread_info_callback callback; 329 thread_info_callback callback;
269 }; 330 };
270 331
271 // callback function for libthread_db 332 // callback function for libthread_db
272 static int thread_db_callback(const td_thrhandle_t *th_p, void *data) { 333 static int thread_db_callback(const td_thrhandle_t *th_p, void *data) {
273 struct thread_db_client_data* ptr = (struct thread_db_client_data*) data; 334 struct thread_db_client_data* ptr = (struct thread_db_client_data*) data;
312 // delete thread agent 373 // delete thread agent
313 td_ta_delete(thread_agent); 374 td_ta_delete(thread_agent);
314 return true; 375 return true;
315 } 376 }
316 377
378 #endif // __APPLE__
317 379
318 // get number of threads 380 // get number of threads
319 int get_num_threads(struct ps_prochandle* ph) { 381 int get_num_threads(struct ps_prochandle* ph) {
320 return ph->num_threads; 382 return ph->num_threads;
321 } 383 }
322 384
323 // get lwp_id of n'th thread 385 // get lwp_id of n'th thread
324 lwpid_t get_lwp_id(struct ps_prochandle* ph, int index) { 386 lwpid_t get_lwp_id(struct ps_prochandle* ph, int index) {
325 int count = 0; 387 int count = 0;
326 thread_info* thr = ph->threads; 388 sa_thread_info* thr = ph->threads;
327 while (thr) { 389 while (thr) {
328 if (count == index) { 390 if (count == index) {
329 return thr->lwp_id; 391 return thr->lwp_id;
330 } 392 }
331 count++; 393 count++;
332 thr = thr->next; 394 thr = thr->next;
333 } 395 }
334 return -1; 396 return 0;
335 } 397 }
398
399 #ifdef __APPLE__
400 // set lwp_id of n'th thread
401 bool set_lwp_id(struct ps_prochandle* ph, int index, lwpid_t lwpid) {
402 int count = 0;
403 sa_thread_info* thr = ph->threads;
404 while (thr) {
405 if (count == index) {
406 thr->lwp_id = lwpid;
407 return true;
408 }
409 count++;
410 thr = thr->next;
411 }
412 return false;
413 }
414
415 // get regs of n-th thread, only used in fillThreads the first time called
416 bool get_nth_lwp_regs(struct ps_prochandle* ph, int index, struct reg* regs) {
417 int count = 0;
418 sa_thread_info* thr = ph->threads;
419 while (thr) {
420 if (count == index) {
421 break;
422 }
423 count++;
424 thr = thr->next;
425 }
426 if (thr != NULL) {
427 memcpy(regs, &thr->regs, sizeof(struct reg));
428 return true;
429 }
430 return false;
431 }
432
433 #endif // __APPLE__
336 434
337 // get regs for a given lwp 435 // get regs for a given lwp
338 bool get_lwp_regs(struct ps_prochandle* ph, lwpid_t lwp_id, struct reg* regs) { 436 bool get_lwp_regs(struct ps_prochandle* ph, lwpid_t lwp_id, struct reg* regs) {
339 return ph->ops->get_lwp_regs(ph, lwp_id, regs); 437 return ph->ops->get_lwp_regs(ph, lwp_id, regs);
340 } 438 }
341 439
342 // get number of shared objects 440 // get number of shared objects
343 int get_num_libs(struct ps_prochandle* ph) { 441 int get_num_libs(struct ps_prochandle* ph) {
344 return ph->num_libs; 442 return ph->num_libs;
345 } 443 }
346 444
347 // get name of n'th solib 445 // get name of n'th solib
348 const char* get_lib_name(struct ps_prochandle* ph, int index) { 446 const char* get_lib_name(struct ps_prochandle* ph, int index) {
349 int count = 0; 447 int count = 0;
350 lib_info* lib = ph->libs; 448 lib_info* lib = ph->libs;
351 while (lib) { 449 while (lib) {
352 if (count == index) { 450 if (count == index) {
353 return lib->name; 451 return lib->name;
354 } 452 }
355 count++; 453 count++;
356 lib = lib->next; 454 lib = lib->next;
357 } 455 }
358 return NULL; 456 return NULL;
359 } 457 }
360 458
361 // get base address of a lib 459 // get base address of a lib
362 uintptr_t get_lib_base(struct ps_prochandle* ph, int index) { 460 uintptr_t get_lib_base(struct ps_prochandle* ph, int index) {
363 int count = 0; 461 int count = 0;
364 lib_info* lib = ph->libs; 462 lib_info* lib = ph->libs;
365 while (lib) { 463 while (lib) {
366 if (count == index) { 464 if (count == index) {
367 return lib->base; 465 return lib->base;
368 } 466 }
369 count++; 467 count++;
370 lib = lib->next; 468 lib = lib->next;
371 } 469 }
372 return (uintptr_t)NULL; 470 return (uintptr_t)NULL;
373 } 471 }
374 472
375 bool find_lib(struct ps_prochandle* ph, const char *lib_name) { 473 bool find_lib(struct ps_prochandle* ph, const char *lib_name) {
376 lib_info *p = ph->libs; 474 lib_info *p = ph->libs;
377 while (p) { 475 while (p) {
423 va_start(alist, format); 521 va_start(alist, format);
424 vfprintf(stderr, format, alist); 522 vfprintf(stderr, format, alist);
425 va_end(alist); 523 va_end(alist);
426 } 524 }
427 525
526 #ifndef __APPLE__
428 // ------------------------------------------------------------------------ 527 // ------------------------------------------------------------------------
429 // Functions below this point are not yet implemented. They are here only 528 // Functions below this point are not yet implemented. They are here only
430 // to make the linker happy. 529 // to make the linker happy.
431 530
432 ps_err_e ps_lsetfpregs(struct ps_prochandle *ph, lwpid_t lid, const prfpregset_t *fpregs) { 531 ps_err_e ps_lsetfpregs(struct ps_prochandle *ph, lwpid_t lid, const prfpregset_t *fpregs) {
456 555
457 ps_err_e ps_pcontinue(struct ps_prochandle *ph) { 556 ps_err_e ps_pcontinue(struct ps_prochandle *ph) {
458 print_debug("ps_pcontinue not implemented\n"); 557 print_debug("ps_pcontinue not implemented\n");
459 return PS_OK; 558 return PS_OK;
460 } 559 }
560 #endif // __APPLE__