コード例 #1
0
ファイル: module.c プロジェクト: djmott/dynamorio
/* view_size can be the size of the first mapping, to handle non-contiguous
 * modules -- we'll update the module's size here
 */
void
os_module_area_init(module_area_t *ma, app_pc base, size_t view_size, bool at_map,
                    const char *filepath, uint64 inode HEAPACCT(which_heap_t which))
{
    app_pc mod_base, mod_end;
    ptr_int_t load_delta;
    char *soname = NULL;
    ASSERT(module_is_header(base, view_size));

    /* i#1589: use privload data if it exists (for client lib) */
    if (!privload_fill_os_module_info(base, &mod_base, &mod_end, &soname, &ma->os_data)) {
        /* XXX i#1860: on Android we'll fail to fill in info from .dynamic, so
         * we'll have incomplete data until the loader maps the segment with .dynamic.
         * ma->os_data.have_dynamic_info indicates whether we have the info.
         */
        module_walk_program_headers(base, view_size, at_map,
                                    !at_map, /* i#1589: ld.so relocates .dynamic */
                                    &mod_base, NULL, &mod_end, &soname, &ma->os_data);
    }
    if (ma->os_data.contiguous) {
        app_pc map_end = ma->os_data.segments[ma->os_data.num_segments - 1].end;
        module_list_add_mapping(ma, base, map_end);
        /* update, since may just be 1st segment size */
        ma->end = map_end;
    } else {
        /* Add the non-contiguous segments (i#160/PR 562667).  We could just add
         * them all separately but vmvectors are more efficient with fewer
         * entries so we merge.  We don't want general merging in our vector
         * either.
         */
        app_pc seg_base;
        uint i;
        ASSERT(ma->os_data.num_segments > 0 && ma->os_data.segments != NULL);
        seg_base = ma->os_data.segments[0].start;
        for (i = 1; i < ma->os_data.num_segments; i++) {
            if (ma->os_data.segments[i].start > ma->os_data.segments[i - 1].end ||
                /* XXX: for shared we just add the first one.  But if the first
                 * module is unloaded we'll be missing an entry for the others.
                 * We assume this won't happen b/c our only use of this now is
                 * the MacOS dyld shared cache's shared __LINKEDIT segment.  If
                 * it could happen we should switch to a refcount in the vector.
                 */
                ma->os_data.segments[i - 1].shared) {
                if (!ma->os_data.segments[i - 1].shared ||
                    !vmvector_overlap(loaded_module_areas, seg_base,
                                      ma->os_data.segments[i - 1].end)) {
                    module_list_add_mapping(ma, seg_base,
                                            ma->os_data.segments[i - 1].end);
                }
                seg_base = ma->os_data.segments[i].start;
            }
        }
        if (!ma->os_data.segments[i - 1].shared ||
            !vmvector_overlap(loaded_module_areas, seg_base,
                              ma->os_data.segments[i - 1].end))
            module_list_add_mapping(ma, seg_base, ma->os_data.segments[i - 1].end);
        DOLOG(2, LOG_VMAREAS, {
            LOG(GLOBAL, LOG_INTERP | LOG_VMAREAS, 2, "segment list\n");
            for (i = 0; i < ma->os_data.num_segments; i++) {
                LOG(GLOBAL, LOG_INTERP | LOG_VMAREAS, 2,
                    "\tsegment %d: [" PFX "," PFX ") prot=%x\n", i,
                    ma->os_data.segments[i].start, ma->os_data.segments[i].end,
                    ma->os_data.segments[i].prot);
            }
        });
コード例 #2
0
ファイル: memquery.c プロジェクト: DynamoRIO/drk
/* 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;
}