blob: 71d799ba90fa033897e959c6ff5964555ae99b36 [file] [log] [blame]
/* *******************************************************************************
* Copyright (c) 2010-2014 Google, Inc. All rights reserved.
* Copyright (c) 2011 Massachusetts Institute of Technology All rights reserved.
* Copyright (c) 2000-2010 VMware, Inc. All rights reserved.
* *******************************************************************************/
/*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* * Neither the name of VMware, Inc. nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL VMWARE, INC. OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
/*
* memquery.c - memory querying code shared across unix platforms
*/
#include "../globals.h"
#include "memquery.h"
#include "module.h"
#include <string.h>
/***************************************************************************
* LIBRARY BOUNDS
*/
/* 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;
}