int value_reify(struct value *val, struct value_dict *arguments) { if (val->where != VAL_LOC_INFERIOR) return 0; assert(val->inferior != NULL); size_t size = value_size(val, arguments); if (size == (size_t)-1) return -1; void *data; enum value_location_t nloc; if (size <= sizeof(val->u.value)) { data = &val->u.value; nloc = VAL_LOC_WORD; } else { data = malloc(size); if (data == NULL) return -1; nloc = VAL_LOC_COPY; } if (umovebytes(val->inferior, val->u.inf_address, data, size) < size) { if (nloc == VAL_LOC_COPY) free(data); return -1; } val->where = nloc; if (nloc == VAL_LOC_COPY) val->u.address = data; return 0; }
static int find_dynamic_entry_addr(Process *proc, void *pvAddr, int d_tag, void **addr) { int i = 0, done = 0; ElfW(Dyn) entry; debug(DEBUG_FUNCTION, "find_dynamic_entry()"); if (addr == NULL || pvAddr == NULL || d_tag < 0 || d_tag > DT_NUM) { return -1; } while ((!done) && (i < ELF_MAX_SEGMENTS) && (sizeof(entry) == umovebytes(proc, pvAddr, &entry, sizeof(entry))) && (entry.d_tag != DT_NULL)) { if (entry.d_tag == d_tag) { done = 1; *addr = (void *)entry.d_un.d_val; } pvAddr += sizeof(entry); i++; } if (done) { debug(2, "found address: 0x%p in dtag %d\n", *addr, d_tag); return 0; } else { debug(2, "Couldn't address for dtag!\n"); return -1; } }
static int fetch_rd64(struct Process *proc, arch_addr_t addr, struct lt_r_debug_64 *ret) { if (umovebytes(proc, addr, ret, sizeof(*ret)) != sizeof(*ret)) return -1; return 0; }
static int fetch_lm64(struct Process *proc, arch_addr_t addr, struct lt_link_map_64 *ret) { if (umovebytes(proc, addr, ret, sizeof(*ret)) != sizeof(*ret)) return -1; return 0; }
static int fetch_dyn64(struct Process *proc, arch_addr_t *addr, Elf64_Dyn *ret) { if (umovebytes(proc, *addr, ret, sizeof(*ret)) != sizeof(*ret)) return -1; *addr += sizeof(*ret); return 0; }
static void crawl_linkmap(Process *proc, struct r_debug *dbg, void (*callback)(void *), struct cb_data *data) { struct link_map rlm; char lib_name[BUFSIZ]; struct link_map *lm = NULL; debug (DEBUG_FUNCTION, "crawl_linkmap()"); if (!dbg || !dbg->r_map) { debug(2, "Debug structure or it's linkmap are NULL!"); return; } lm = dbg->r_map; while (lm) { if (umovebytes(proc, lm, &rlm, sizeof(rlm)) != sizeof(rlm)) { debug(2, "Unable to read link map\n"); return; } lm = rlm.l_next; if (rlm.l_name == NULL) { debug(2, "Invalid library name referenced in dynamic linker map\n"); return; } umovebytes(proc, rlm.l_name, lib_name, sizeof(lib_name)); if (lib_name[0] == '\0') { debug(2, "Library name is an empty string"); continue; } if (callback) { debug(2, "Dispatching callback for: %s, " "Loaded at 0x%" PRI_ELF_ADDR "\n", lib_name, rlm.l_addr); data->addr = rlm.l_addr; data->lib_name = lib_name; callback(data); } } return; }
static int fetch_dyn32(struct Process *proc, arch_addr_t *addr, Elf64_Dyn *ret) { Elf32_Dyn dyn; if (umovebytes(proc, *addr, &dyn, sizeof(dyn)) != sizeof(dyn)) return -1; *addr += sizeof(dyn); ret->d_tag = dyn.d_tag; ret->d_un.d_val = dyn.d_un.d_val; return 0; }
static int fetch_rd32(struct Process *proc, arch_addr_t addr, struct lt_r_debug_64 *ret) { struct lt_r_debug_32 rd; if (umovebytes(proc, addr, &rd, sizeof(rd)) != sizeof(rd)) return -1; ret->r_version = rd.r_version; ret->r_map = rd.r_map; ret->r_brk = rd.r_brk; ret->r_state = rd.r_state; ret->r_ldbase = rd.r_ldbase; return 0; }
static int fetch_lm32(struct Process *proc, arch_addr_t addr, struct lt_link_map_64 *ret) { struct lt_link_map_32 lm; if (umovebytes(proc, addr, &lm, sizeof(lm)) != sizeof(lm)) return -1; ret->l_addr = lm.l_addr; ret->l_name = lm.l_name; ret->l_ld = lm.l_ld; ret->l_next = lm.l_next; ret->l_prev = lm.l_prev; return 0; }
int arch_find_dl_debug(struct Process *proc, arch_addr_t dyn_addr, arch_addr_t *ret) { arch_addr_t rld_addr; int r; /* MIPS puts the address of the r_debug structure into the * DT_MIPS_RLD_MAP entry instead of into the DT_DEBUG entry. */ r = proc_find_dynamic_entry_addr(proc, dyn_addr, DT_MIPS_RLD_MAP, &rld_addr); if (r == 0) { if (umovebytes(proc, rld_addr, ret, sizeof *ret) != sizeof *ret) { r = -1; } } return r; }
static struct r_debug * load_debug_struct(Process *proc) { struct r_debug *rdbg = NULL; debug(DEBUG_FUNCTION, "load_debug_struct"); rdbg = malloc(sizeof(*rdbg)); if (!rdbg) { return NULL; } if (umovebytes(proc, proc->debug, rdbg, sizeof(*rdbg)) != sizeof(*rdbg)) { debug(2, "This process does not have a debug structure!\n"); free(rdbg); return NULL; } return rdbg; }
static void crawl_linkmap(struct Process *proc, struct lt_r_debug_64 *dbg) { debug (DEBUG_FUNCTION, "crawl_linkmap()"); if (!dbg || !dbg->r_map) { debug(2, "Debug structure or it's linkmap are NULL!"); return; } /* XXX The double cast should be removed when * arch_addr_t becomes integral type. */ arch_addr_t addr = (arch_addr_t)(uintptr_t)dbg->r_map; while (addr != 0) { struct lt_link_map_64 rlm = {}; if (lm_fetcher(proc)(proc, addr, &rlm) < 0) { debug(2, "Unable to read link map"); return; } arch_addr_t key = addr; /* XXX The double cast should be removed when * arch_addr_t becomes integral type. */ addr = (arch_addr_t)(uintptr_t)rlm.l_next; if (rlm.l_name == 0) { debug(2, "Name of mapped library is NULL"); return; } char lib_name[BUFSIZ]; /* XXX The double cast should be removed when * arch_addr_t becomes integral type. */ umovebytes(proc, (arch_addr_t)(uintptr_t)rlm.l_name, lib_name, sizeof(lib_name)); /* Library name can be an empty string, in which case * the entry represents either the main binary, or a * VDSO. Unfortunately we can't rely on that, as in * recent glibc, that entry is initialized to VDSO * SONAME. * * It's not clear how to detect VDSO in this case. We * can't assume that l_name of real DSOs will be * either absolute or relative (for LD_LIBRARY_PATH=: * it will be neither). We can't compare l_addr with * AT_SYSINFO_EHDR either, as l_addr is bias (which * also means it's not unique, and therefore useless * for this). We could load VDSO from process image * and at least compare actual SONAMEs. For now, this * kludge is about the best that we can do. */ if (*lib_name == 0 || strcmp(lib_name, "linux-vdso.so.1") == 0 || strcmp(lib_name, "linux-gate.so.1") == 0 || strcmp(lib_name, "linux-vdso32.so.1") == 0 || strcmp(lib_name, "linux-vdso64.so.1") == 0) continue; /* Do we have that library already? */ if (proc_each_library(proc, NULL, library_with_key_cb, &key)) continue; struct library *lib = malloc(sizeof(*lib)); if (lib == NULL) { fail: if (lib != NULL) library_destroy(lib); fprintf(stderr, "Couldn't load ELF object %s: %s\n", lib_name, strerror(errno)); continue; } library_init(lib, LT_LIBTYPE_DSO); if (ltelf_read_library(lib, proc, lib_name, rlm.l_addr) < 0) goto fail; lib->key = key; proc_add_library(proc, lib); } return; }
int arch_fetch_arg_next(struct fetch_context *ctx, enum tof type, struct process *proc, struct arg_type_info *info, struct value *valuep) { const size_t sz = type_sizeof(proc, info); assert(sz != (size_t)-1); if (ctx->hardfp && !ctx->in_varargs) { int rc; if ((rc = consider_vfp(ctx, proc, info, valuep)) != 1) return rc; } /* IHI0042E_aapcs: If the argument requires double-word * alignment (8-byte), the NCRN is rounded up to the next even * register number. */ const size_t al = type_alignof(proc, info); assert(al != (size_t)-1); if (al == 8) ctx->ncrn = ((ctx->ncrn + 1) / 2) * 2; /* If the size in words of the argument is not more than r4 * minus NCRN, the argument is copied into core registers, * starting at the NCRN. */ /* If the NCRN is less than r4 and the NSAA is equal to the * SP, the argument is split between core registers and the * stack. */ const size_t words = (sz + 3) / 4; if (ctx->ncrn < 4 && ctx->nsaa == ctx->sp) { unsigned char *data = value_reserve(valuep, words * 4); if (data == NULL) return -1; size_t i; for (i = 0; i < words && ctx->ncrn < 4; ++i) { memcpy(data, &ctx->regs.uregs[ctx->ncrn++], 4); data += 4; } const size_t rest = (words - i) * 4; if (rest > 0) { umovebytes(proc, ctx->nsaa, data, rest); ctx->nsaa += rest; } return 0; } assert(ctx->ncrn == 4); /* If the argument required double-word alignment (8-byte), * then the NSAA is rounded up to the next double-word * address. */ if (al == 8) /* XXX double cast. */ ctx->nsaa = (arch_addr_t)((((uintptr_t)ctx->nsaa + 7) / 8) * 8); else ctx->nsaa = (arch_addr_t)((((uintptr_t)ctx->nsaa + 3) / 4) * 4); value_in_inferior(valuep, ctx->nsaa); ctx->nsaa += sz; return 0; }