bool memquery_from_os(const byte *pc, OUT dr_mem_info_t *info, OUT bool *have_type) { memquery_iter_t iter; app_pc last_end = NULL; app_pc next_start = (app_pc) POINTER_MAX; bool found = false; ASSERT(info != NULL); memquery_iterator_start(&iter, (app_pc) pc, false/*won't alloc*/); while (memquery_iterator_next(&iter)) { if (pc >= iter.vm_start && pc < iter.vm_end) { info->base_pc = iter.vm_start; info->size = (iter.vm_end - iter.vm_start); info->prot = iter.prot; /* On early (pre-Fedora 2) kernels the vsyscall page is listed * with no permissions at all in the maps file. Here's RHEL4: * ffffe000-fffff000 ---p 00000000 00:00 0 * We return "rx" as the permissions in that case. */ if (vsyscall_page_start != NULL && pc >= vsyscall_page_start && pc < vsyscall_page_start+PAGE_SIZE) { /* i#1583: recent kernels have 2-page vdso, which can be split, * but we don't expect to come here b/c they won't have zero * permissions. */ ASSERT(iter.vm_start == vsyscall_page_start); ASSERT(iter.vm_end - iter.vm_start == PAGE_SIZE || /* i386 Ubuntu 14.04: * 0xb77bc000-0xb77be000 0x2000 0x0 [vvar] * 0xb77be000-0xb77c0000 0x2000 0x0 [vdso] */ iter.vm_end - iter.vm_start == 2*PAGE_SIZE); info->prot = (MEMPROT_READ|MEMPROT_EXEC|MEMPROT_VDSO); } else if (strcmp(iter.comment, "[vvar]") == 0) { /* The VVAR pages were added in kernel 3.0 but not labeled until * 3.15. We document that we do not label prior to 3.15. * DrMem#1778 seems to only happen on 3.19+ in any case. */ info->prot |= MEMPROT_VDSO; } found = true; break; } else if (pc < iter.vm_start) { next_start = iter.vm_start; break; } last_end = iter.vm_end; } memquery_iterator_stop(&iter); if (!found) { info->base_pc = last_end; info->size = (next_start - last_end); info->prot = MEMPROT_NONE; info->type = DR_MEMTYPE_FREE; *have_type = true; } return true; }
/* See memquery.h for full interface specs, which are identical to * memquery_library_bounds(). */ int memquery_library_bounds_by_iterator(const char *name, app_pc *start/*IN/OUT*/, app_pc *end/*OUT*/, char *fullpath/*OPTIONAL OUT*/, size_t path_size) { int count = 0; bool found_library = false; char libname[MAXIMUM_PATH]; const char *name_cmp = name; memquery_iter_t iter; app_pc last_base = NULL; app_pc last_end = NULL; size_t image_size = 0; app_pc cur_end = NULL; app_pc mod_start = NULL; ASSERT(name != NULL || start != NULL); /* If name is non-NULL, start can be NULL, so we have to walk the whole * address space even when we have syscalls for memquery (e.g., on Mac). * Even if start is non-NULL, it could be in the middle of the library. */ memquery_iterator_start(&iter, NULL, /* We're never called from a fragile place like a * signal handler, so as long as it's not real early * it's ok to alloc. */ dynamo_heap_initialized); libname[0] = '\0'; while (memquery_iterator_next(&iter)) { LOG(GLOBAL, LOG_VMAREAS, 5, "start="PFX" end="PFX" prot=%x comment=%s\n", iter.vm_start, iter.vm_end, iter.prot, iter.comment); /* Record the base of each differently-named set of entries up until * we find our target, when we'll clobber libpath */ if (!found_library && strncmp(libname, iter.comment, BUFFER_SIZE_ELEMENTS(libname)) != 0) { last_base = iter.vm_start; /* last_end is used to know what's readable beyond last_base */ if (TEST(MEMPROT_READ, iter.prot)) last_end = iter.vm_end; else last_end = last_base; /* remember name so we can find the base of a multiply-mapped so */ strncpy(libname, iter.comment, BUFFER_SIZE_ELEMENTS(libname)); NULL_TERMINATE_BUFFER(libname); } if ((name_cmp != NULL && (strstr(iter.comment, name_cmp) != NULL || /* For Linux, include mid-library (non-.bss) anonymous mappings. * Our private loader * fills mapping holes with anonymous memory instead of a * MEMPROT_NONE mapping from the original file. * For Mac, this includes mid-library .bss. */ (found_library && iter.comment[0] == '\0' && image_size != 0 && iter.vm_end - mod_start < image_size))) || (name == NULL && *start >= iter.vm_start && *start < iter.vm_end)) { if (!found_library) { size_t mod_readable_sz; char *dst = (fullpath != NULL) ? fullpath : libname; size_t dstsz = (fullpath != NULL) ? path_size : BUFFER_SIZE_ELEMENTS(libname); char *slash = strrchr(iter.comment, '/'); ASSERT_CURIOSITY(slash != NULL); ASSERT_CURIOSITY((slash - iter.comment) < dstsz); /* we keep the last '/' at end */ ++slash; strncpy(dst, iter.comment, MIN(dstsz, (slash - iter.comment))); /* if max no null */ dst[dstsz - 1] = '\0'; if (name == NULL) name_cmp = dst; found_library = true; /* Most library have multiple segments, and some have the * ELF header repeated in a later mapping, so we can't rely * on is_elf_so_header() and header walking. * We use the name tracking to remember the first entry * that had this name. */ if (last_base == NULL) { mod_start = iter.vm_start; mod_readable_sz = iter.vm_end - iter.vm_start; } else { mod_start = last_base; mod_readable_sz = last_end - last_base; } if (module_is_header(mod_start, mod_readable_sz)) { app_pc mod_base, mod_end; if (module_walk_program_headers(mod_start, mod_readable_sz, false, &mod_base, NULL, &mod_end, NULL, NULL)) { image_size = mod_end - mod_base; LOG(GLOBAL, LOG_VMAREAS, 4, "%s: image size is "PIFX"\n", __FUNCTION__, image_size); ASSERT_CURIOSITY(image_size != 0); } else { ASSERT_NOT_REACHED(); } } else { ASSERT(false && "expected elf header"); } } count++; cur_end = iter.vm_end; } else if (found_library) { /* hit non-matching, we expect module segments to be adjacent */ break; } } /* Xref PR 208443: .bss sections are anonymous (no file name listed in * maps file), but not every library has one. We have to parse the ELF * header to know since we can't assume that a subsequent anonymous * region is .bss. */ if (image_size != 0 && cur_end - mod_start < image_size) { /* Found a .bss section. Check current mapping (note might only be * part of the mapping (due to os region merging? FIXME investigate). */ ASSERT_CURIOSITY(iter.vm_start == cur_end /* no gaps, FIXME might there be * a gap if the file has large * alignment and no data section? * curiosity for now*/); ASSERT_CURIOSITY(iter.inode == 0); /* .bss is anonymous */ ASSERT_CURIOSITY(iter.vm_end - mod_start >= image_size);/* should be big enough */ count++; cur_end = mod_start + image_size; } else { /* Shouldn't have more mapped then the size of the module, unless it's a * second adjacent separate map of the same file. Curiosity for now. */ ASSERT_CURIOSITY(image_size == 0 || cur_end - mod_start == image_size); } memquery_iterator_stop(&iter); if (start != NULL) *start = mod_start; if (end != NULL) *end = cur_end; return count; }