Skip to content

Commit

Permalink
i#58 MacOS: more Mach-O support
Browse files Browse the repository at this point in the history
Share the core of module_add_segment_data() with ELF and call it for Mach-O
when iterating segments.

SVN-Revision: 2470
  • Loading branch information
derekbruening committed Jan 9, 2014
1 parent 4c38531 commit 0d6abe2
Show file tree
Hide file tree
Showing 6 changed files with 142 additions and 78 deletions.
17 changes: 1 addition & 16 deletions core/unix/memquery_macos.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@

#include "../globals.h"
#include "memquery.h"
#include "memquery_macos.h"
#include "os_private.h"

#include <mach/mach.h>
Expand Down Expand Up @@ -148,22 +149,6 @@ memquery_iterator_stop(memquery_iter_t *iter)
mutex_unlock(&memquery_backing_lock);
}

/* Translate mach flags to memprot flags. They happen to equal the mmap
* flags, but best to not rely on that.
*/
static inline uint
vmprot_to_memprot(uint prot)
{
uint mem_prot = 0;
if (TEST(VM_PROT_EXECUTE, prot))
mem_prot |= MEMPROT_EXEC;
if (TEST(VM_PROT_READ, prot))
mem_prot |= MEMPROT_READ;
if (TEST(VM_PROT_WRITE, prot))
mem_prot |= MEMPROT_WRITE;
return mem_prot;
}

bool
memquery_iterator_next(memquery_iter_t *iter)
{
Expand Down
56 changes: 56 additions & 0 deletions core/unix/memquery_macos.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/* *******************************************************************************
* Copyright (c) 2014 Google, 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 Google, 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_macos.h - Mac-specific memory utilities
*/

#ifndef _MEMQUERY_MACOS_H_
#define _MEMQUERY_MACOS_H_ 1

/* Translate mach flags to memprot flags. They happen to equal the mmap
* flags, but best to not rely on that.
*/
static inline uint
vmprot_to_memprot(uint prot)
{
uint mem_prot = 0;
if (TEST(VM_PROT_EXECUTE, prot))
mem_prot |= MEMPROT_EXEC;
if (TEST(VM_PROT_READ, prot))
mem_prot |= MEMPROT_READ;
if (TEST(VM_PROT_WRITE, prot))
mem_prot |= MEMPROT_WRITE;
return mem_prot;
}

#endif /* _MEMQUERY_MACOS_H_ */
59 changes: 58 additions & 1 deletion core/unix/module.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* *******************************************************************************
* Copyright (c) 2012-2013 Google, Inc. All rights reserved.
* Copyright (c) 2012-2014 Google, Inc. All rights reserved.
* Copyright (c) 2011 Massachusetts Institute of Technology All rights reserved.
* Copyright (c) 2008-2010 VMware, Inc. All rights reserved.
* *******************************************************************************/
Expand Down Expand Up @@ -410,6 +410,63 @@ os_module_get_rct_htable(app_pc pc, rct_type_t which)
}
#endif

/* Adds an entry for a segment to the out_data->segments array */
void
module_add_segment_data(OUT os_module_data_t *out_data,
uint num_segments /*hint only*/,
app_pc segment_start,
size_t segment_size,
uint segment_prot, /* MEMPROT_ */
size_t alignment)
{
uint seg, i;
if (out_data->alignment == 0) {
out_data->alignment = alignment;
} else {
/* We expect all segments to have the same alignment */
ASSERT_CURIOSITY(out_data->alignment == alignment);
}
/* Add segments to the module vector (i#160/PR 562667).
* For !HAVE_MEMINFO we should combine w/ the segment
* walk done in dl_iterate_get_areas_cb().
*/
if (out_data->num_segments == 0) {
/* over-allocate to avoid 2 passes to count PT_LOAD */
out_data->alloc_segments = (num_segments == 0 ? 4 : num_segments);
out_data->segments = (module_segment_t *)
HEAP_ARRAY_ALLOC(GLOBAL_DCONTEXT, module_segment_t,
out_data->alloc_segments, ACCT_OTHER, PROTECTED);
out_data->contiguous = true;
}
/* Keep array sorted in addr order. I'm assuming segments are disjoint! */
for (i = 0; i < out_data->num_segments; i++) {
if (out_data->segments[i].start > segment_start)
break;
}
seg = i;
/* Shift remaining entries */
for (i = out_data->num_segments; i > seg; i++) {
out_data->segments[i] = out_data->segments[i - 1];
}
out_data->num_segments++;
ASSERT(out_data->num_segments <= out_data->alloc_segments);
/* ELF requires p_vaddr to already be aligned to p_align */
out_data->segments[seg].start = (app_pc) ALIGN_BACKWARD(segment_start, PAGE_SIZE);
out_data->segments[seg].end = (app_pc)
ALIGN_FORWARD(segment_start + segment_size, PAGE_SIZE);
out_data->segments[seg].prot = segment_prot;
if (seg > 0) {
ASSERT(out_data->segments[seg].start >= out_data->segments[seg - 1].end);
if (out_data->segments[seg].start > out_data->segments[seg - 1].end)
out_data->contiguous = false;
}
if (seg < out_data->num_segments - 1) {
ASSERT(out_data->segments[seg + 1].start >= out_data->segments[seg].end);
if (out_data->segments[seg + 1].start > out_data->segments[seg].end)
out_data->contiguous = false;
}
}

/* Returns true if the module has an nth segment, false otherwise. */
bool
module_get_nth_segment(app_pc module_base, uint n,
Expand Down
10 changes: 9 additions & 1 deletion core/unix/module.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* **********************************************************
* Copyright (c) 2011-2013 Google, Inc. All rights reserved.
* Copyright (c) 2011-2014 Google, Inc. All rights reserved.
* Copyright (c) 2008-2010 VMware, Inc. All rights reserved.
* **********************************************************/

Expand Down Expand Up @@ -116,6 +116,14 @@ module_file_is_module64(file_t f);
bool
module_get_platform(file_t f, dr_platform_t *platform);

void
module_add_segment_data(OUT os_module_data_t *out_data,
uint num_segments /*hint only*/,
app_pc segment_start,
size_t segment_size,
uint segment_prot,
size_t alignment);

/* Redirected functions for loaded module,
* they are also used by __wrap_* functions in instrument.c
*/
Expand Down
65 changes: 6 additions & 59 deletions core/unix/module_elf.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* *******************************************************************************
* Copyright (c) 2012-2013 Google, Inc. All rights reserved.
* Copyright (c) 2012-2014 Google, Inc. All rights reserved.
* Copyright (c) 2011 Massachusetts Institute of Technology All rights reserved.
* Copyright (c) 2008-2010 VMware, Inc. All rights reserved.
* *******************************************************************************/
Expand Down Expand Up @@ -311,62 +311,6 @@ module_segment_prot_to_osprot(ELF_PROGRAM_HEADER_TYPE *prog_hdr)

#ifndef NOT_DYNAMORIO_CORE_PROPER

/* Adds an entry for a segment to the out_data->segments array */
static void
module_add_segment_data(OUT os_module_data_t *out_data,
ELF_HEADER_TYPE *elf_hdr,
ptr_int_t load_delta,
ELF_PROGRAM_HEADER_TYPE *prog_hdr)
{
uint seg, i;
if (out_data->alignment == 0) {
out_data->alignment = prog_hdr->p_align;
} else {
/* We expect all segments to have the same alignment */
ASSERT_CURIOSITY(out_data->alignment == prog_hdr->p_align);
}
/* Add segments to the module vector (i#160/PR 562667).
* For !HAVE_MEMINFO we should combine w/ the segment
* walk done in dl_iterate_get_areas_cb().
*/
if (out_data->num_segments == 0) {
/* over-allocate to avoid 2 passes to count PT_LOAD */
out_data->alloc_segments = elf_hdr->e_phnum;
out_data->segments = (module_segment_t *)
HEAP_ARRAY_ALLOC(GLOBAL_DCONTEXT, module_segment_t,
out_data->alloc_segments, ACCT_OTHER, PROTECTED);
out_data->contiguous = true;
}
/* Keep array sorted in addr order. I'm assuming segments are disjoint! */
for (i = 0; i < out_data->num_segments; i++) {
if (out_data->segments[i].start > (app_pc)prog_hdr->p_vaddr + load_delta)
break;
}
seg = i;
/* Shift remaining entries */
for (i = out_data->num_segments; i > seg; i++) {
out_data->segments[i] = out_data->segments[i - 1];
}
out_data->num_segments++;
ASSERT(out_data->num_segments <= out_data->alloc_segments);
/* ELF requires p_vaddr to already be aligned to p_align */
out_data->segments[seg].start = (app_pc)
ALIGN_BACKWARD(prog_hdr->p_vaddr + load_delta, PAGE_SIZE);
out_data->segments[seg].end = (app_pc)
ALIGN_FORWARD(prog_hdr->p_vaddr + load_delta + prog_hdr->p_memsz, PAGE_SIZE);
out_data->segments[seg].prot = module_segment_prot_to_osprot(prog_hdr);
if (seg > 0) {
ASSERT(out_data->segments[seg].start >= out_data->segments[seg - 1].end);
if (out_data->segments[seg].start > out_data->segments[seg - 1].end)
out_data->contiguous = false;
}
if (seg < out_data->num_segments - 1) {
ASSERT(out_data->segments[seg + 1].start >= out_data->segments[seg].end);
if (out_data->segments[seg + 1].start > out_data->segments[seg].end)
out_data->contiguous = false;
}
}

/* common code to fill os_module_data_t for loader and module_area_t */
static void
module_fill_os_data(ELF_PROGRAM_HEADER_TYPE *prog_hdr, /* PT_DYNAMIC entry */
Expand Down Expand Up @@ -519,8 +463,11 @@ module_walk_program_headers(app_pc base, size_t view_size, bool at_map,
(base + elf_hdr->e_phoff + i * elf_hdr->e_phentsize);
if (prog_hdr->p_type == PT_LOAD) {
if (out_data != NULL) {
module_add_segment_data(out_data, elf_hdr,
load_delta, prog_hdr);
module_add_segment_data(out_data, elf_hdr->e_phnum,
(app_pc) prog_hdr->p_vaddr + load_delta,
prog_hdr->p_memsz,
module_segment_prot_to_osprot(prog_hdr),
prog_hdr->p_align);
}
found_load = true;
}
Expand Down
13 changes: 12 additions & 1 deletion core/unix/module_macho.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
#include "../module_shared.h"
#include "os_private.h"
#include "module_private.h"
#include "memquery_macos.h"
#include <mach-o/ldsyms.h> /* _mh_dylib_header */
#include <mach-o/loader.h> /* mach_header */
#include <stddef.h> /* offsetof */
Expand Down Expand Up @@ -129,7 +130,7 @@ module_walk_program_headers(app_pc base, size_t view_size, bool at_map,
{
mach_header_t *hdr = (mach_header_t *) base;
struct load_command *cmd, *cmd_stop;
app_pc seg_min_start = base + view_size;
app_pc seg_min_start = base + (view_size == 0 ? PAGE_SIZE : view_size);
app_pc seg_max_end = base;
bool found_seg = false;
ASSERT(is_macho_header(base, view_size));
Expand All @@ -150,6 +151,16 @@ module_walk_program_headers(app_pc base, size_t view_size, bool at_map,
* perhaps share some code there?).
* We also need to fill in out_data (like ELF module_fill_os_data).
*/
if (out_data != NULL) {
module_add_segment_data(out_data, 0/*don't know*/,
(app_pc) seg->vmaddr, seg->vmsize,
/* assuming we want initprot and not maxprot */
vmprot_to_memprot(seg->initprot),
/* XXX: alignment is specified per section --
* ignoring for now
*/
PAGE_SIZE);
}
} else if (cmd->cmd == LC_ID_DYLIB) {
struct dylib_command *dy = (struct dylib_command *) cmd;
char *soname = (char *)cmd + dy->dylib.name.offset;
Expand Down

0 comments on commit 0d6abe2

Please sign in to comment.