static int find_start(jvm_agent_t* J, uint64_t ptr, uint64_t *startp) { int err; int i; for (i = 0; i < J->Number_of_heaps; ++i) { *startp = 0; if (codeheap_contains(i, J, ptr)) { int32_t used; uint64_t segment = segment_for(i, J, ptr); uint64_t block = J->Heap_segmap_low[i]; uint8_t tag; err = ps_pread(J->P, block + segment, &tag, sizeof(tag)); CHECK_FAIL(err); if (tag == 0xff) return PS_OK; while (tag > 0) { err = ps_pread(J->P, block + segment, &tag, sizeof(tag)); CHECK_FAIL(err); segment -= tag; } block = block_at(i, J, segment); err = ps_pread(J->P, block + OFFSET_HeapBlockHeader_used, &used, sizeof(used)); CHECK_FAIL(err); if (used) { *startp = block + SIZE_HeapBlockHeader; } } return PS_OK; } fail: return -1; }
static int find_start(jvm_agent_t* J, uint64_t ptr, uint64_t *startp) { int err; *startp = 0; if (J->CodeCache_low <= ptr && ptr < J->CodeCache_high) { int32_t used; uint64_t segment = segment_for(J, ptr); uint64_t block = J->CodeCache_segmap_low; uint8_t tag; err = ps_pread(J->P, block + segment, &tag, sizeof(tag)); CHECK_FAIL(err); if (tag == 0xff) return PS_OK; while (tag > 0) { err = ps_pread(J->P, block + segment, &tag, sizeof(tag)); CHECK_FAIL(err); segment -= tag; } block = block_at(J, segment); err = ps_pread(J->P, block + OFFSET_HeapBlockHeader_used, &used, sizeof(used)); CHECK_FAIL(err); if (used) { *startp = block + SIZE_HeapBlockHeader; } } return PS_OK; fail: return -1; }
void print_mem(struct ps_prochandle * ph, ulong_t address, int count, char * format) { printf("\n%17s:", print_address_ps(ph, address, FLG_PAP_SONAME)); if ((*format == 'X') || (*format == 'x')) { int i; for (i = 0; i < count; i++) { unsigned long word; if ((i % 4) == 0) printf("\n 0x%08lx: ", address); if (ps_pread(ph, address, (char *)&word, sizeof (unsigned long)) != PS_OK) { printf("\nfailed to read memory at: 0x%lx\n", address); return; } printf(" 0x%08lx", word); address += 4; } putchar('\n'); return; } if (*format == 'b') { int i; for (i = 0; i < count; i++, address ++) { unsigned char byte; if ((i % 8) == 0) printf("\n 0x%08lx: ", address); if (ps_pread(ph, address, (char *)&byte, sizeof (unsigned char)) != PS_OK) { fprintf(stderr, "\nfailed to read byte " "at: 0x%lx\n", address); return; } printf(" %02x", (unsigned)byte); } putchar('\n'); return; } if (*format == 's') { char buf[MAXPATHLEN]; if (proc_string_read(ph, address, buf, MAXPATHLEN) != RET_OK) { printf("unable to read string at: %s\n", address); return; } printf(" %s\n", buf); return; } }
/* * Given the address of an ELF object in the target, return its size and * the proper link map ID. */ static size_t lx_elf_props32(struct ps_prochandle *php, uint32_t addr, psaddr_t *data_addr) { Elf32_Ehdr ehdr; Elf32_Phdr *phdrs, *ph; int i; uint32_t min = (uint32_t)-1; uint32_t max = 0; size_t sz = NULL; if (ps_pread(php, addr, &ehdr, sizeof (ehdr)) != PS_OK) { ps_plog("lx_elf_props: Couldn't read ELF header at 0x%p", addr); return (0); } if ((phdrs = malloc(ehdr.e_phnum * ehdr.e_phentsize)) == NULL) return (0); if (ps_pread(php, addr + ehdr.e_phoff, phdrs, ehdr.e_phnum * ehdr.e_phentsize) != PS_OK) { ps_plog("lx_elf_props: Couldn't read program headers at 0x%p", addr + ehdr.e_phoff); return (0); } for (i = 0, ph = phdrs; i < ehdr.e_phnum; i++, /*LINTED */ ph = (Elf32_Phdr *)((char *)ph + ehdr.e_phentsize)) { if (ph->p_type != PT_LOAD) continue; if ((ph->p_flags & (PF_W | PF_R)) == (PF_W | PF_R)) { *data_addr = ph->p_vaddr; if (ehdr.e_type == ET_DYN) *data_addr += addr; if (*data_addr & (ph->p_align - 1)) *data_addr = *data_addr & (~(ph->p_align -1)); } if (ph->p_vaddr < min) min = ph->p_vaddr; if (ph->p_vaddr > max) { max = ph->p_vaddr; sz = ph->p_memsz + max - min; if (sz & (ph->p_align - 1)) sz = (sz & (~(ph->p_align - 1))) + ph->p_align; } } free(phdrs); return (sz); }
static int read_pointer(jvm_agent_t* J, uint64_t base, uint64_t* ptr) { int err = -1; uint32_t ptr32; switch (DATA_MODEL) { case PR_MODEL_LP64: err = ps_pread(J->P, base, ptr, sizeof(uint64_t)); break; case PR_MODEL_ILP32: err = ps_pread(J->P, base, &ptr32, sizeof(uint32_t)); *ptr = ptr32; break; } return err; }
retc_t disasm_addr(struct ps_prochandle * ph, ulong_t addr, int num_inst) { ulong_t offset; ulong_t end; int vers = V8_MODE; if (ph->pp_dmodel == PR_MODEL_LP64) vers = V9_MODE | V9_SGI_MODE; for (offset = addr, end = addr + num_inst * 4; offset < end; offset += 4) { char * instr_str; unsigned int instr; if (ps_pread(ph, offset, (char *)&instr, sizeof (unsigned)) != PS_OK) perror("da: ps_pread"); cur_ph = ph; instr_str = disassemble(instr, offset, print_address, 0, 0, vers); printf("%-30s: %s\n", print_address(offset), instr_str); } return (RET_OK); }
static int read_compressed_pointer(jvm_agent_t* J, uint64_t base, uint32_t *ptr) { int err = -1; uint32_t ptr32; err = ps_pread(J->P, base, &ptr32, sizeof(uint32_t)); *ptr = ptr32; return err; }
rd_err_e rd_loadobj_iter (rd_agent_t *rdap, rl_iter_f *cb, void *clnt_data) { ps_err_e res; /* Read r_debug. */ struct r_debug r_debug; res = ps_pread (rdap->rd_php, (psaddr_t)rdap->rd_r_debug, &r_debug, sizeof (r_debug)); if (res != PS_OK) return RD_DBERR; struct link_map *r_map_ptr = (struct link_map *)r_debug.r_map; while (r_map_ptr) { /* Read in the current r_map. */ struct link_map r_map; res = ps_pread (rdap->rd_php, (psaddr_t)r_map_ptr, &r_map, sizeof (r_map)); if (res != PS_OK) return RD_DBERR; /* Fill in rd_loadobj_t. */ rd_loadobj_t loadobj = {0}; loadobj.rl_nameaddr = (psaddr_t)r_map.l_name; loadobj.rl_flags = 0; if (r_map.l_relocated) loadobj.rl_flags |= RD_FLG_MEM_OBJECT; loadobj.rl_base = r_map.l_addr; loadobj.rl_data_base = (psaddr_t)r_map.l_phdr; loadobj.rl_lmident = r_map.l_ns; /* pl_refnameaddr is unused. */ /* rl_plt_base and rl_plt_size are unused. */ /* TODO: do we need to worry about these (added in rtld_db v3)? */ loadobj.rl_bend = 0; //r_map.l_map_end; loadobj.rl_padstart = 0; //r_map.l_map_start; loadobj.rl_padend = 0; //r_map.l_map_end; loadobj.rl_dynamic = (psaddr_t)r_map.l_ld; if (cb (&loadobj, clnt_data) == 0) break; r_map_ptr = r_map.l_next; } return RD_OK; }
static int raw_read_int(jvm_agent_t* J, uint64_t *buffer, int32_t *val) { int shift = 0; int value = 0; uint8_t ch = 0; int32_t err; int32_t sum; // Constants for UNSIGNED5 coding of Pack200 // see compressedStream.hpp enum { lg_H = 6, H = 1<<lg_H, BitsPerByte = 8, L = (1<<BitsPerByte)-H, }; int i; err = ps_pread(J->P, (*buffer)++, &ch, sizeof(uint8_t)); CHECK_FAIL(err); if (debug > 2) fprintf(stderr, "\t\t\t raw_read_int: *buffer: %#llx, ch: %#x\n", *buffer, ch); sum = ch; if ( sum >= L ) { int32_t lg_H_i = lg_H; // Read maximum of 5 total bytes (we've already read 1). // See CompressedReadStream::read_int_mb for ( i = 0; i < 4; i++) { err = ps_pread(J->P, (*buffer)++, &ch, sizeof(uint8_t)); CHECK_FAIL(err); sum += ch << lg_H_i; if (ch < L ) { *val = sum; return PS_OK; } lg_H_i += lg_H; } } *val = sum; return PS_OK; fail: return err; }
static bool read_pointer(struct ps_prochandle* ph, psaddr_t addr, uintptr_t* pvalue) { uintptr_t uip; if (ps_pread(ph, addr, &uip, sizeof(uip)) == PS_OK) { *pvalue = uip; return true; } else { return false; } }
static bool read_jboolean(struct ps_prochandle* ph, psaddr_t addr, jboolean* pvalue) { jboolean i; if (ps_pread(ph, addr, &i, sizeof(i)) == PS_OK) { *pvalue = i; return true; } else { return false; } }
static int find_jlong_constant(jvm_agent_t* J, const char *name, uint64_t* valuep) { psaddr_t sym_addr; int err = ps_pglobal_lookup(J->P, LIBJVM_SO, name, &sym_addr); if (err == PS_OK) { err = ps_pread(J->P, sym_addr, valuep, sizeof(uint64_t)); return err; } *valuep = -1; return -1; }
static int read_volatiles(jvm_agent_t* J) { uint64_t ptr; int err; err = find_symbol(J, "UseCompressedOops", &J->Use_Compressed_Oops_address); if (err == PS_OK) { err = ps_pread(J->P, J->Use_Compressed_Oops_address, &J->Use_Compressed_Oops, sizeof(uint8_t)); CHECK_FAIL(err); } else { J->Use_Compressed_Oops = 0; } err = read_pointer(J, J->Universe_narrow_oop_base_address, &J->Universe_narrow_oop_base); CHECK_FAIL(err); err = ps_pread(J->P, J->Universe_narrow_oop_shift_address, &J->Universe_narrow_oop_shift, sizeof(uint32_t)); CHECK_FAIL(err); err = read_pointer(J, J->CodeCache_heap_address + OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low, &J->CodeCache_low); CHECK_FAIL(err); err = read_pointer(J, J->CodeCache_heap_address + OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high, &J->CodeCache_high); CHECK_FAIL(err); err = read_pointer(J, J->CodeCache_heap_address + OFFSET_CodeHeap_segmap + OFFSET_VirtualSpace_low, &J->CodeCache_segmap_low); CHECK_FAIL(err); err = read_pointer(J, J->CodeCache_heap_address + OFFSET_CodeHeap_segmap + OFFSET_VirtualSpace_high, &J->CodeCache_segmap_high); CHECK_FAIL(err); err = ps_pread(J->P, J->CodeCache_heap_address + OFFSET_CodeHeap_log2_segment_size, &J->SIZE_CodeCache_log2_segment, sizeof(J->SIZE_CodeCache_log2_segment)); CHECK_FAIL(err); return PS_OK; fail: return err; }
static int read_pair(jvm_agent_t* J, uint64_t *buffer, int32_t *bci, int32_t *line) { uint8_t next = 0; int32_t bci_delta; int32_t line_delta; int32_t err; if (debug > 2) fprintf(stderr, "\t\t read_pair: BEGIN\n"); err = ps_pread(J->P, (*buffer)++, &next, sizeof(uint8_t)); CHECK_FAIL(err); if (next == 0) { if (debug > 2) fprintf(stderr, "\t\t read_pair: END: next == 0\n"); return 1; /* stream terminated */ } if (next == 0xFF) { if (debug > 2) fprintf(stderr, "\t\t read_pair: END: next == 0xFF\n"); /* Escape character, regular compression used */ err = raw_read_int(J, buffer, &bci_delta); CHECK_FAIL(err); err = raw_read_int(J, buffer, &line_delta); CHECK_FAIL(err); *bci += bci_delta; *line += line_delta; if (debug > 2) { fprintf(stderr, "\t\t read_pair: delta = (line %d: %d)\n", line_delta, bci_delta); fprintf(stderr, "\t\t read_pair: unpack= (line %d: %d)\n", *line, *bci); } } else { /* Single byte compression used */ *bci += next >> 3; *line += next & 0x7; if (debug > 2) { fprintf(stderr, "\t\t read_pair: delta = (line %d: %d)\n", next & 0x7, next >> 3); fprintf(stderr, "\t\t read_pair: unpack= (line %d: %d)\n", *line, *bci); } }
/* * Class: sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal * Method: readBytesFromProcess0 * Signature: (JJ)Lsun/jvm/hotspot/debugger/ReadResult; */ JNIEXPORT jbyteArray JNICALL Java_sun_jvm_hotspot_debugger_bsd_BsdDebuggerLocal_readBytesFromProcess0 (JNIEnv *env, jobject this_obj, jlong addr, jlong numBytes) { jboolean isCopy; jbyteArray array; jbyte *bufPtr; ps_err_e err; array = (*env)->NewByteArray(env, numBytes); CHECK_EXCEPTION_(0); bufPtr = (*env)->GetByteArrayElements(env, array, &isCopy); CHECK_EXCEPTION_(0); err = ps_pread(get_proc_handle(env, this_obj), (psaddr_t) (uintptr_t)addr, bufPtr, numBytes); (*env)->ReleaseByteArrayElements(env, array, bufPtr, 0); return (err == PS_OK)? array : 0; }
static int read_string(struct ps_prochandle *P, char *buf, /* caller's buffer */ size_t size, /* upper limit on bytes to read */ uintptr_t addr) /* address in process */ { int err = PS_OK; while (size-- > 1 && err == PS_OK) { err = ps_pread(P, addr, buf, 1); if (*buf == '\0') { return PS_OK; } addr += 1; buf += 1; } return -1; }
/* * Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal * Method: readBytesFromProcess0 * Signature: (JJ)Lsun/jvm/hotspot/debugger/ReadResult; */ JNIEXPORT jbyteArray JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_readBytesFromProcess0 (JNIEnv *env, jobject this_obj, jlong address, jlong numBytes) { jbyteArray array = env->NewByteArray(numBytes); CHECK_EXCEPTION_(0); jboolean isCopy; jbyte* bufPtr = env->GetByteArrayElements(array, &isCopy); CHECK_EXCEPTION_(0); jlong ps_prochandle_ptr = env->GetLongField(this_obj, ps_prochandle_ptr_ID); ps_err_e ret = ps_pread((struct ps_prochandle*) ps_prochandle_ptr, (psaddr_t)address, bufPtr, (size_t)numBytes); if(ret != PS_OK) { // Part of workaround for 4705086. jint libjvm_fd = env->GetIntField(this_obj, libjvm_fd_ID); jlong libjvm_text_start = env->GetLongField(this_obj, libjvm_text_start_ID); jlong libjvm_text_size = env->GetLongField(this_obj, libjvm_text_size_ID); // get the file descriptor for libjvm.so jlong offset = address - libjvm_text_start; // do bounds check to verify that the given address is in // libjvm text if (offset >= libjvm_text_size || offset < 0) { env->ReleaseByteArrayElements(array, bufPtr, JNI_COMMIT); // the address given is not in libjvm[_g].so text return jbyteArray(0); } ssize_t bytes_read = pread(libjvm_fd, bufPtr, numBytes, (off_t)offset); if (bytes_read != (ssize_t) numBytes) { env->ReleaseByteArrayElements(array, bufPtr, JNI_COMMIT); return jbyteArray(0); } } env->ReleaseByteArrayElements(array, bufPtr, JNI_COMMIT); return array; }
static bool read_string(struct ps_prochandle* ph, psaddr_t addr, char* buf, size_t size) { char ch = ' '; size_t i = 0; while (ch != '\0') { if (ps_pread(ph, addr, &ch, sizeof(ch)) != PS_OK) return false; if (i < size - 1) { buf[i] = ch; } else { // smaller buffer return false; } i++; addr++; } buf[i] = '\0'; return true; }
static int lx_ldb_loadobj_iter32(rd_helper_data_t rhd, rl_iter_f *cb, void *client_data) { lx_rd_t *lx_rd = (lx_rd_t *)rhd; struct ps_prochandle *php = lx_rd->lr_php; lx_r_debug_t r_debug; lx_link_map_t map; uint32_t p = NULL; int rc; rd_loadobj_t exec; if ((rc = ps_pread(php, (psaddr_t)lx_rd->lr_rdebug, &r_debug, sizeof (r_debug))) != PS_OK) { ps_plog("lx_ldb_loadobj_iter: " "Couldn't read linux r_debug at 0x%p", lx_rd->lr_rdebug); return (rc); } p = r_debug.r_map; /* * The first item on the link map list is for the executable, but it * doesn't give us any useful information about it. We need to * synthesize a rd_loadobj_t for the client. * * Linux doesn't give us the executable name, so we'll get it from * the AT_EXECNAME entry instead. */ if ((rc = ps_pread(php, (psaddr_t)p, &map, sizeof (map))) != PS_OK) { ps_plog("lx_ldb_loadobj_iter: " "Couldn't read linux link map at 0x%p", p); return (rc); } bzero(&exec, sizeof (exec)); exec.rl_base = lx_rd->lr_exec; exec.rl_dynamic = map.lxm_ld; exec.rl_nameaddr = lx_ldb_getauxval32(php, AT_SUN_EXECNAME); exec.rl_lmident = LM_ID_BASE; exec.rl_bend = exec.rl_base + lx_elf_props32(php, lx_rd->lr_exec, &exec.rl_data_base); if ((*cb)(&exec, client_data) == 0) { ps_plog("lx_ldb_loadobj_iter: " "client callb failed for executable"); return (PS_ERR); } for (p = map.lxm_next; p != NULL; p = map.lxm_next) { rd_loadobj_t obj; if ((rc = ps_pread(php, (psaddr_t)p, &map, sizeof (map))) != PS_OK) { ps_plog("lx_ldb_loadobj_iter: " "Couldn't read lk map at %p", p); return (rc); } /* * The linux link map has less information than the Solaris one. * We need to go fetch the missing information from the ELF * headers. */ obj.rl_nameaddr = (psaddr_t)map.lxm_name; obj.rl_base = map.lxm_addr; obj.rl_refnameaddr = (psaddr_t)map.lxm_name; obj.rl_plt_base = NULL; obj.rl_plt_size = 0; obj.rl_lmident = LM_ID_BASE; /* * Ugh - we have to walk the ELF stuff, find the PT_LOAD * sections, and calculate the end of the file's mappings * ourselves. */ obj.rl_bend = map.lxm_addr + lx_elf_props32(php, map.lxm_addr, &obj.rl_data_base); obj.rl_padstart = obj.rl_base; obj.rl_padend = obj.rl_bend; obj.rl_dynamic = map.lxm_ld; obj.rl_tlsmodid = 0; ps_plog("lx_ldb_loadobj_iter: 0x%p to 0x%p", obj.rl_base, obj.rl_bend); if ((*cb)(&obj, client_data) == 0) { ps_plog("lx_ldb_loadobj_iter: " "Client callback failed on %s", map.lxm_name); return (rc); } } return (RD_OK); }
/* ARGSUSED 3 */ rd_err_e plt64_resolution(rd_agent_t *rap, psaddr_t pc, lwpid_t lwpid, psaddr_t pltbase, rd_plt_info_t *rpi) { uint32_t pcrel; psaddr_t destaddr; psaddr_t pltoff, pltaddr; if (rtld_db_version >= RD_VERSION3) { rpi->pi_flags = 0; rpi->pi_baddr = 0; } pltoff = pc - pltbase; pltaddr = pltbase + ((pltoff / M_PLT_ENTSIZE) * M_PLT_ENTSIZE); /* * This is the target of the jmp instruction */ if (ps_pread(rap->rd_psp, pltaddr + 2, (char *)&pcrel, sizeof (pcrel)) != PS_OK) { LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_2), EC_ADDR(pltaddr + 2))); return (RD_ERR); } /* * the offset to the GOT table entry is * PC-relative. */ destaddr = pcrel + pltaddr + 6; /* * Find out what's pointed to by @OFFSET_INTO_GOT */ if (ps_pread(rap->rd_psp, destaddr, (char *)&destaddr, sizeof (destaddr)) != PS_OK) { LOG(ps_plog(MSG_ORIG(MSG_DB_READFAIL_2), EC_ADDR(destaddr))); return (RD_ERR); } if (destaddr == (pltaddr + 6)) { rd_err_e rerr; /* * If GOT[ind] points to PLT+6 then this is the first * time through this PLT. */ if ((rerr = rd_binder_exit_addr(rap, MSG_ORIG(MSG_SYM_RTBIND), &(rpi->pi_target))) != RD_OK) { return (rerr); } rpi->pi_skip_method = RD_RESOLVE_TARGET_STEP; rpi->pi_nstep = 1; } else { /* * This is the n'th time through and GOT[ind] points * to the final destination. */ rpi->pi_skip_method = RD_RESOLVE_STEP; rpi->pi_nstep = 1; rpi->pi_target = 0; if (rtld_db_version >= RD_VERSION3) { rpi->pi_flags |= RD_FLG_PI_PLTBOUND; rpi->pi_baddr = destaddr; } } return (RD_OK); }
/* * The linux linker has an r_debug structure somewhere in its data section that * contains the address of the head of the link map list. To find this, we will * use the DT_DEBUG token in the executable's dynamic section. The linux linker * wrote the address of its r_debug structure to the DT_DEBUG dynamic entry. We * get the address of the executable's program headers from the * AT_SUN_BRAND_LX_PHDR aux vector entry. From there, we calculate the * address of the Elf header, and from there we can easily get to the DT_DEBUG * entry. */ static rd_helper_data_t lx_ldb_init32(rd_agent_t *rap, struct ps_prochandle *php) { lx_rd_t *lx_rd; uint32_t addr, phdr_addr, dyn_addr; uint32_t symtab, strtab, offs; uint32_t vaddr, memsz; caddr_t mem; Elf32_Dyn *dyn; Elf32_Phdr phdr, *ph, *dph, *phdrs; Elf32_Ehdr ehdr; Elf32_Sym *sym; int i, dyn_count; lx_rd = calloc(sizeof (lx_rd_t), 1); if (lx_rd == NULL) { ps_plog("lx_ldb_init: cannot allocate memory"); return (NULL); } lx_rd->lr_rap = rap; lx_rd->lr_php = php; phdr_addr = lx_ldb_getauxval32(php, AT_SUN_BRAND_LX_PHDR); if (phdr_addr == (uint32_t)-1) { ps_plog("lx_ldb_init: no LX_PHDR found in aux vector"); return (NULL); } ps_plog("lx_ldb_init: found LX_PHDR auxv phdr at: 0x%p", phdr_addr); if (ps_pread(php, phdr_addr, &phdr, sizeof (phdr)) != PS_OK) { ps_plog("lx_ldb_init: couldn't read phdr at 0x%p", phdr_addr); free(lx_rd); return (NULL); } /* The ELF header should be before the program header in memory */ lx_rd->lr_exec = addr = phdr_addr - phdr.p_offset; if (ps_pread(php, addr, &ehdr, sizeof (ehdr)) != PS_OK) { ps_plog("lx_ldb_init: couldn't read ehdr at 0x%p", lx_rd->lr_exec); free(lx_rd); return (NULL); } ps_plog("lx_ldb_init: read ehdr at: 0x%p", addr); if ((phdrs = malloc(ehdr.e_phnum * ehdr.e_phentsize)) == NULL) { ps_plog("lx_ldb_init: couldn't alloc phdrs memory"); free(lx_rd); return (NULL); } if (ps_pread(php, phdr_addr, phdrs, ehdr.e_phnum * ehdr.e_phentsize) != PS_OK) { ps_plog("lx_ldb_init: couldn't read phdrs at 0x%p", phdr_addr); free(lx_rd); free(phdrs); return (NULL); } ps_plog("lx_ldb_init: read %d phdrs at: 0x%p", ehdr.e_phnum, phdr_addr); for (i = 0, ph = phdrs; i < ehdr.e_phnum; i++, /*LINTED */ ph = (Elf32_Phdr *)((char *)ph + ehdr.e_phentsize)) { if (ph->p_type == PT_DYNAMIC) break; } if (i == ehdr.e_phnum) { ps_plog("lx_ldb_init: no PT_DYNAMIC in executable"); free(lx_rd); free(phdrs); return (NULL); } ps_plog("lx_ldb_init: found PT_DYNAMIC phdr[%d] at: 0x%p", i, (phdr_addr + ((char *)ph - (char *)phdrs))); if ((dyn = malloc(ph->p_filesz)) == NULL) { ps_plog("lx_ldb_init: couldn't alloc for PT_DYNAMIC"); free(lx_rd); free(phdrs); return (NULL); } dyn_addr = addr + ph->p_offset; dyn_count = ph->p_filesz / sizeof (Elf32_Dyn); if (ps_pread(php, dyn_addr, dyn, ph->p_filesz) != PS_OK) { ps_plog("lx_ldb_init: couldn't read dynamic at 0x%p", dyn_addr); free(lx_rd); free(phdrs); free(dyn); return (NULL); } ps_plog("lx_ldb_init: read %d dynamic headers at: 0x%p", dyn_count, dyn_addr); for (i = 0; i < dyn_count; i++) { if (dyn[i].d_tag == DT_DEBUG) { lx_rd->lr_rdebug = dyn[i].d_un.d_ptr; break; } } free(phdrs); free(dyn); if (lx_rd->lr_rdebug != 0) { ps_plog("lx_ldb_init: found DT_DEBUG: 0x%p", lx_rd->lr_rdebug); return ((rd_helper_data_t)lx_rd); } ps_plog("lx_ldb_init: no DT_DEBUG found in exe; looking for r_debug"); /* * If we didn't find DT_DEBUG, we're going to employ the same fallback * as gdb: pawing through the dynamic linker's symbol table looking * for the r_debug symbol. */ addr = lx_ldb_getauxval32(php, AT_SUN_BRAND_LX_INTERP); if (addr == (uint32_t)-1) { ps_plog("lx_ldb_init: no interpreter; failing"); free(lx_rd); return (NULL); } ps_plog("lx_ldb_init: reading interp ehdr at 0x%p", addr); if (ps_pread(php, addr, &ehdr, sizeof (ehdr)) != PS_OK) { ps_plog("lx_ldb_init: couldn't read interp ehdr at 0x%p", addr); free(lx_rd); return (NULL); } if (ehdr.e_type != ET_DYN) { ps_plog("lx_ldb_init: interp ehdr not of type ET_DYN"); free(lx_rd); return (NULL); } phdr_addr = addr + ehdr.e_phoff; if ((phdrs = malloc(ehdr.e_phnum * ehdr.e_phentsize)) == NULL) { ps_plog("lx_ldb_init: couldn't alloc interp phdrs memory"); free(lx_rd); return (NULL); } if (ps_pread(php, phdr_addr, phdrs, ehdr.e_phnum * ehdr.e_phentsize) != PS_OK) { ps_plog("lx_ldb_init: couldn't read interp phdrs at 0x%p", phdr_addr); free(lx_rd); free(phdrs); return (NULL); } ps_plog("lx_ldb_init: read %d interp phdrs at: 0x%p", ehdr.e_phnum, phdr_addr); vaddr = (uint32_t)-1; memsz = 0; for (i = 0, ph = phdrs, dph = NULL; i < ehdr.e_phnum; i++, /*LINTED */ ph = (Elf32_Phdr *)((char *)ph + ehdr.e_phentsize)) { /* * Keep track of our lowest PT_LOAD address, as this segment * contains the DT_SYMTAB and DT_STRTAB. */ if (ph->p_type == PT_LOAD && ph->p_vaddr < vaddr) { vaddr = ph->p_vaddr; memsz = ph->p_memsz; } if (ph->p_type == PT_DYNAMIC) dph = ph; } if (vaddr == (uint32_t)-1 || memsz == 0) { ps_plog("lx_ldb_init: no PT_LOAD section in interp"); free(lx_rd); free(phdrs); return (NULL); } ps_plog("lx_ldb_init: found interp PT_LOAD to be %d bytes at 0x%p", memsz, vaddr); if ((ph = dph) == NULL) { ps_plog("lx_ldb_init: no PT_DYNAMIC in interp"); free(lx_rd); free(phdrs); return (NULL); } ps_plog("lx_ldb_init: found interp PT_DYNAMIC phdr[%d] at: 0x%p", i, (phdr_addr + ((char *)ph - (char *)phdrs))); if ((dyn = malloc(ph->p_filesz)) == NULL) { ps_plog("lx_ldb_init: couldn't alloc for interp PT_DYNAMIC"); free(lx_rd); free(phdrs); return (NULL); } dyn_addr = addr + ph->p_offset; dyn_count = ph->p_filesz / sizeof (Elf32_Dyn); if (ps_pread(php, dyn_addr, dyn, ph->p_filesz) != PS_OK) { ps_plog("lx_ldb_init: couldn't read interp dynamic at 0x%p", dyn_addr); free(lx_rd); free(phdrs); free(dyn); return (NULL); } free(phdrs); ps_plog("lx_ldb_init: read %d interp dynamic headers at: 0x%p", dyn_count, dyn_addr); /* * As noted in lx_ldb_get_dyns32(), in Linux, the PT_DYNAMIC table * is adjusted to represent absolute addresses instead of offsets. * This is not true for the interpreter, however -- where the values * will be represented as offsets from the lowest PT_LOAD p_vaddr. */ symtab = strtab = (uint32_t)-1; for (i = 0; i < dyn_count; i++) { if (dyn[i].d_tag == DT_STRTAB) strtab = dyn[i].d_un.d_ptr - vaddr; if (dyn[i].d_tag == DT_SYMTAB) symtab = dyn[i].d_un.d_ptr - vaddr; } free(dyn); if (strtab == (uint32_t)-1 || strtab > memsz) { ps_plog("lx_ldb_init: didn't find valid interp strtab"); free(lx_rd); return (NULL); } if (symtab == (uint32_t)-1 || symtab > memsz) { ps_plog("lx_ldb_init: didn't find valid interp symtab"); free(lx_rd); return (NULL); } ps_plog("lx_ldb_init: strtab is 0x%x, symtab is 0x%x", addr + strtab, addr + symtab); if ((mem = malloc(memsz)) == NULL) { ps_plog("lx_ldb_init: couldn't allocate interp " "buffer of 0x%p bytes", memsz); free(lx_rd); return (NULL); } if (ps_pread(php, addr, mem, memsz) != PS_OK) { ps_plog("lx_ldb_init: couldn't read interp at 0x%p", addr); free(lx_rd); free(mem); return (NULL); } /* * We make an assumption that is made elsewhere in the Linux linker: * that the DT_SYMTAB immediately precedes the DT_STRTAB. */ for (offs = symtab; offs < strtab; offs += sizeof (Elf32_Sym)) { sym = (Elf32_Sym *)&mem[offs]; if (sym->st_name > memsz) { ps_plog("lx_ldb_init: invalid st_name at sym 0x%p", addr + offs); } ps_plog("lx_ldb_init: found interp symbol %s", &mem[strtab + sym->st_name]); if (strcmp(&mem[strtab + sym->st_name], "_r_debug") == 0) break; } if (offs >= strtab) { ps_plog("lx_ldb_init: no _r_debug found in interpreter"); free(mem); free(lx_rd); return (NULL); } lx_rd->lr_rdebug = (sym->st_value - vaddr) + addr; ps_plog("lx_ldb_init: found _r_debug at 0x%p", lx_rd->lr_rdebug); free(mem); return ((rd_helper_data_t)lx_rd); }
static int nmethod_info(Nmethod_t *N) { jvm_agent_t *J = N->J; uint64_t nm = N->nm; int32_t err; if (debug > 2 ) fprintf(stderr, "\t nmethod_info: BEGIN \n"); /* Instructions */ err = ps_pread(J->P, nm + OFFSET_CodeBlob_code_offset, &N->instrs_beg, SZ32); CHECK_FAIL(err); err = ps_pread(J->P, nm + OFFSET_CodeBlob_data_offset, &N->instrs_end, SZ32); CHECK_FAIL(err); err = ps_pread(J->P, nm + OFFSET_nmethod_deoptimize_offset, &N->deopt_beg, SZ32); CHECK_FAIL(err); err = ps_pread(J->P, nm + OFFSET_nmethod_orig_pc_offset, &N->orig_pc_offset, SZ32); CHECK_FAIL(err); /* Metadata */ err = ps_pread(J->P, nm + OFFSET_nmethod_metadata_offset, &N->metadata_beg, SZ32); CHECK_FAIL(err); err = ps_pread(J->P, nm + OFFSET_nmethod_scopes_data_offset, &N->metadata_end, SZ32); CHECK_FAIL(err); /* scopes_pcs */ err = ps_pread(J->P, nm + OFFSET_nmethod_scopes_pcs_offset, &N->scopes_pcs_beg, SZ32); CHECK_FAIL(err); err = ps_pread(J->P, nm + OFFSET_nmethod_dependencies_offset, &N->scopes_pcs_end, SZ32); CHECK_FAIL(err); /* scopes_data */ err = ps_pread(J->P, nm + OFFSET_nmethod_scopes_data_offset, &N->scopes_data_beg, SZ32); CHECK_FAIL(err); if (debug > 2 ) { N->scopes_data_end = N->scopes_pcs_beg; fprintf(stderr, "\t nmethod_info: instrs_beg: %#x, instrs_end: %#x\n", N->instrs_beg, N->instrs_end); fprintf(stderr, "\t nmethod_info: deopt_beg: %#x \n", N->deopt_beg); fprintf(stderr, "\t nmethod_info: orig_pc_offset: %#x \n", N->orig_pc_offset); fprintf(stderr, "\t nmethod_info: metadata_beg: %#x, metadata_end: %#x\n", N->metadata_beg, N->metadata_end); fprintf(stderr, "\t nmethod_info: scopes_data_beg: %#x, scopes_data_end: %#x\n", N->scopes_data_beg, N->scopes_data_end); fprintf(stderr, "\t nmethod_info: scopes_pcs_beg: %#x, scopes_pcs_end: %#x\n", N->scopes_pcs_beg, N->scopes_pcs_end); fprintf(stderr, "\t nmethod_info: END \n\n"); } return PS_OK; fail: return err; }
static int name_for_methodPtr(jvm_agent_t* J, uint64_t methodPtr, char * result, size_t size) { short nameIndex; short signatureIndex; uint64_t constantPool; uint64_t constMethod; uint64_t nameSymbol; uint64_t signatureSymbol; uint64_t klassPtr; uint64_t klassSymbol; short klassSymbolLength; short nameSymbolLength; short signatureSymbolLength; char * nameString = NULL; char * klassString = NULL; char * signatureString = NULL; int err; err = read_pointer(J, methodPtr + OFFSET_Method_constMethod, &constMethod); CHECK_FAIL(err); err = read_pointer(J, constMethod + OFFSET_ConstMethod_constants, &constantPool); CHECK_FAIL(err); /* To get name string */ err = ps_pread(J->P, constMethod + OFFSET_ConstMethod_name_index, &nameIndex, 2); CHECK_FAIL(err); err = read_pointer(J, constantPool + nameIndex * POINTER_SIZE + SIZE_ConstantPool, &nameSymbol); CHECK_FAIL(err); // The symbol is a CPSlot and has lower bit set to indicate metadata nameSymbol &= (~1); // remove metadata lsb err = ps_pread(J->P, nameSymbol + OFFSET_Symbol_length, &nameSymbolLength, 2); CHECK_FAIL(err); nameString = (char*)calloc(nameSymbolLength + 1, 1); err = ps_pread(J->P, nameSymbol + OFFSET_Symbol_body, nameString, nameSymbolLength); CHECK_FAIL(err); /* To get signature string */ err = ps_pread(J->P, constMethod + OFFSET_ConstMethod_signature_index, &signatureIndex, 2); CHECK_FAIL(err); err = read_pointer(J, constantPool + signatureIndex * POINTER_SIZE + SIZE_ConstantPool, &signatureSymbol); CHECK_FAIL(err); signatureSymbol &= (~1); // remove metadata lsb err = ps_pread(J->P, signatureSymbol + OFFSET_Symbol_length, &signatureSymbolLength, 2); CHECK_FAIL(err); signatureString = (char*)calloc(signatureSymbolLength + 1, 1); err = ps_pread(J->P, signatureSymbol + OFFSET_Symbol_body, signatureString, signatureSymbolLength); CHECK_FAIL(err); /* To get klass string */ err = read_pointer(J, constantPool + OFFSET_ConstantPool_pool_holder, &klassPtr); CHECK_FAIL(err); err = read_pointer(J, klassPtr + OFFSET_Klass_name, &klassSymbol); CHECK_FAIL(err); err = ps_pread(J->P, klassSymbol + OFFSET_Symbol_length, &klassSymbolLength, 2); CHECK_FAIL(err); klassString = (char*)calloc(klassSymbolLength + 1, 1); err = ps_pread(J->P, klassSymbol + OFFSET_Symbol_body, klassString, klassSymbolLength); CHECK_FAIL(err); result[0] = '\0'; if (snprintf(result, size, "%s.%s%s", klassString, nameString, signatureString) >= size) { // truncation goto fail; } if (nameString != NULL) free(nameString); if (klassString != NULL) free(klassString); if (signatureString != NULL) free(signatureString); return PS_OK; fail: if (debug) { fprintf(stderr, "name_for_methodPtr: FAIL \n\n"); } if (nameString != NULL) free(nameString); if (klassString != NULL) free(klassString); if (signatureString != NULL) free(signatureString); return -1; }
/* * Class: sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal * Method: readBytesFromProcess0 * Signature: (JJ)[B * Description: read bytes from debuggee process/core */ JNIEXPORT jbyteArray JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_readBytesFromProcess0 (JNIEnv *env, jobject this_obj, jlong address, jlong numBytes) { jbyteArray array = env->NewByteArray(numBytes); CHECK_EXCEPTION_(0); jboolean isCopy; jbyte* bufPtr = env->GetByteArrayElements(array, &isCopy); CHECK_EXCEPTION_(0); jlong p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID); ps_err_e ret = ps_pread((struct ps_prochandle*) p_ps_prochandle, (psaddr_t)address, bufPtr, (size_t)numBytes); if (ret != PS_OK) { // part of the class sharing workaround. try shared heap area int classes_jsa_fd = env->GetIntField(this_obj, classes_jsa_fd_ID); if (classes_jsa_fd != -1 && address != (jlong)0) { print_debug("read failed at 0x%lx, attempting shared heap area\n", (long) address); struct FileMapHeader* pheader = (struct FileMapHeader*) env->GetLongField(this_obj, p_file_map_header_ID); // walk through the shared mappings -- we just have 4 of them. // so, linear walking is okay. for (int m = 0; m < NUM_SHARED_MAPS; m++) { // We can skip the non-read-only maps. These are mapped as MAP_PRIVATE // and hence will be read by libproc. Besides, the file copy may be // stale because the process might have modified those pages. if (pheader->_space[m]._read_only) { jlong baseAddress = (jlong) (uintptr_t) pheader->_space[m]._base; size_t usedSize = pheader->_space[m]._used; if (address >= baseAddress && address < (baseAddress + usedSize)) { // the given address falls in this shared heap area print_debug("found shared map at 0x%lx\n", (long) baseAddress); // If more data is asked than actually mapped from file, we need to zero fill // till the end-of-page boundary. But, java array new does that for us. we just // need to read as much as data available. #define MIN2(x, y) (((x) < (y))? (x) : (y)) jlong diff = address - baseAddress; jlong bytesToRead = MIN2(numBytes, usedSize - diff); off_t offset = pheader->_space[m]._file_offset + off_t(diff); ssize_t bytesRead = pread(classes_jsa_fd, bufPtr, bytesToRead, offset); if (bytesRead != bytesToRead) { env->ReleaseByteArrayElements(array, bufPtr, JNI_ABORT); print_debug("shared map read failed\n"); return jbyteArray(0); } else { print_debug("shared map read succeeded\n"); env->ReleaseByteArrayElements(array, bufPtr, 0); return array; } } // is in current map } // is read only map } // for shared maps } // classes_jsa_fd != -1 env->ReleaseByteArrayElements(array, bufPtr, JNI_ABORT); return jbyteArray(0); } else { env->ReleaseByteArrayElements(array, bufPtr, 0); return array; } }
static int read_volatiles(jvm_agent_t* J) { int i; uint64_t array_data; uint64_t code_heap_address; int err; err = find_symbol(J, "UseCompressedOops", &J->Use_Compressed_Oops_address); if (err == PS_OK) { err = ps_pread(J->P, J->Use_Compressed_Oops_address, &J->Use_Compressed_Oops, sizeof(uint8_t)); CHECK_FAIL(err); } else { J->Use_Compressed_Oops = 0; } err = read_pointer(J, J->Universe_narrow_oop_base_address, &J->Universe_narrow_oop_base); CHECK_FAIL(err); err = ps_pread(J->P, J->Universe_narrow_oop_shift_address, &J->Universe_narrow_oop_shift, sizeof(uint32_t)); CHECK_FAIL(err); /* CodeCache_heaps_address points to GrowableArray<CodeHeaps*>, read _data field pointing to the first entry of type CodeCache* in the array */ err = read_pointer(J, J->CodeCache_heaps_address + OFFSET_GrowableArray_CodeHeap_data, &array_data); /* Read _len field containing the number of code heaps */ err = ps_pread(J->P, J->CodeCache_heaps_address + OFFSET_GrowableArray_CodeHeap_len, &J->Number_of_heaps, sizeof(J->Number_of_heaps)); /* Allocate memory for heap configurations */ J->Heap_low = (uint64_t*)calloc(J->Number_of_heaps, sizeof(uint64_t)); J->Heap_high = (uint64_t*)calloc(J->Number_of_heaps, sizeof(uint64_t)); J->Heap_segmap_low = (uint64_t*)calloc(J->Number_of_heaps, sizeof(uint64_t)); J->Heap_segmap_high = (uint64_t*)calloc(J->Number_of_heaps, sizeof(uint64_t)); /* Read code heap configurations */ for (i = 0; i < J->Number_of_heaps; ++i) { /* Read address of heap */ err = read_pointer(J, array_data, &code_heap_address); CHECK_FAIL(err); err = read_pointer(J, code_heap_address + OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low, &J->Heap_low[i]); CHECK_FAIL(err); err = read_pointer(J, code_heap_address + OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high, &J->Heap_high[i]); CHECK_FAIL(err); err = read_pointer(J, code_heap_address + OFFSET_CodeHeap_segmap + OFFSET_VirtualSpace_low, &J->Heap_segmap_low[i]); CHECK_FAIL(err); err = read_pointer(J, code_heap_address + OFFSET_CodeHeap_segmap + OFFSET_VirtualSpace_high, &J->Heap_segmap_high[i]); CHECK_FAIL(err); /* Increment pointer to next entry */ array_data = array_data + POINTER_SIZE; } err = ps_pread(J->P, code_heap_address + OFFSET_CodeHeap_log2_segment_size, &J->SIZE_CodeCache_log2_segment, sizeof(J->SIZE_CodeCache_log2_segment)); CHECK_FAIL(err); return PS_OK; fail: return err; }