Пример #1
0
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;
}
Пример #2
0
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;
}
Пример #3
0
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;
	}
}
Пример #4
0
/*
 * 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);
}
Пример #5
0
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;
}
Пример #6
0
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);
}
Пример #7
0
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;
}
Пример #8
0
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;
}
Пример #9
0
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;
}
Пример #10
0
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;
  }
}
Пример #11
0
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;
  }
}
Пример #12
0
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;
}
Пример #13
0
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;
}
Пример #14
0
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);
      }
  }
Пример #15
0
/*
 * 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;
}
Пример #16
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;
}
Пример #17
0
/*
 * 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;
}
Пример #18
0
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;
}
Пример #19
0
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);
}
Пример #20
0
/* 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);
}
Пример #21
0
/*
 * 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);
}
Пример #22
0
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;
}
Пример #23
0
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;
}
Пример #24
0
/*
 * 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;
  }
}
Пример #25
0
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;
}