mirror of
https://github.com/DynamoRIO/dynamorio.git
synced 2026-10-12 10:09:50 +00:00
i#1409 core libs: refactor drhelper+module+file into drlibc (#3398)
Creates a new library of low-level utility functions for system calls,
file i/o, and module parsing from core/ code called "drlibc".
Merges the drhelper library into drlibc.
Creates a new directory core/drlibc/ to group the library files.
Renames lib/drhelper.{c,h} as core/drlibc/drlibc.{c,h}.
Renames the 3 <arch>_shared.asm files to drlibc_<arch>.asm and moves
them into core/drlibc/.
Renames arch/asm_shared.asm to drlibc_xarch.asm and moves it to core/drlibc.
Separates out the module_* and elf_loader_* functionality of
module_{elf,macho}.c that is used by drfrontendlib and drinjectlib
into core/drlibc/drlibc_module_{elf,macho.c}.
Separates out the file i/o functions from unix/os.c that are used by
drfrontendlib and drinjectlib into core/drlibc/drlibc_unix.c.
Adds weak functions to support using LOG, ASSERT, etc. in drlibc code
when linked into non-core binaries via drfrontendlib or drinjectlib
while maintaining the core behavior. For Windows, some of these are
split into their own drlibc_notdr_* files, as the MSVC linker will
discard a duplicate symbol if it's by itself in a single .obj.
Issue: #1409
This commit is contained in:
+44
-26
@@ -91,30 +91,43 @@ if (UNIX AND X86)
|
||||
add_library(drmemfuncs STATIC ${memfuncs_asm_src})
|
||||
endif ()
|
||||
|
||||
# i#1409: to share core code with non-core, we use the "drhelper" library.
|
||||
# XXX: we're using _shared here, and for inject_shared, etc., to mean
|
||||
# "shared between multiple libraries", while we've also started using
|
||||
# _shared on opnd_shared.c, etc. to mean 'shared between architectures":
|
||||
# perhaps we should separate the naming schemes.
|
||||
add_asm_target(arch/asm_shared.asm shared_core_asm_src shared_core_asm_tgt
|
||||
# i#1409: to share core libc-ish code with non-core, we use the "drlibc" library.
|
||||
add_asm_target(drlibc/drlibc_xarch.asm drlibc_xarch_asm_src drlibc_xarch_asm_tgt
|
||||
"_core" "" "${asm_deps}")
|
||||
add_asm_target(arch/${ARCH_NAME}/${ARCH_NAME}_shared.asm shared_arch_asm_src
|
||||
shared_arch_asm_tgt
|
||||
add_asm_target(drlibc/drlibc_${ARCH_NAME}.asm drlibc_arch_asm_src
|
||||
drlibc_arch_asm_tgt
|
||||
"" "" "${asm_deps}")
|
||||
add_library(drhelper STATIC ${shared_core_asm_src} ${shared_arch_asm_src}
|
||||
lib/dr_helper.c)
|
||||
# CMake on Windows fails to link unless we tell it to use the C linker:
|
||||
set_target_properties(drhelper PROPERTIES LINKER_LANGUAGE C)
|
||||
set(DRLIBC_SRCS
|
||||
${drlibc_xarch_asm_src}
|
||||
${drlibc_arch_asm_src}
|
||||
drlibc/drlibc.c
|
||||
drlibc/drlibc_notdr_dcxt.c
|
||||
drlibc/drlibc_notdr_logfile.c
|
||||
drlibc/drlibc_notdr_printlog.c
|
||||
drlibc/drlibc_notdr_report.c
|
||||
drlibc/drlibc_notdr_saferead.c
|
||||
drlibc/drlibc_notdr_stats.c)
|
||||
if (UNIX)
|
||||
append_property_string(TARGET drhelper COMPILE_FLAGS "-fPIC")
|
||||
set(DRLIBC_SRCS ${DRLIBC_SRCS} drlibc/drlibc_unix.c)
|
||||
if (APPLE)
|
||||
set(DRLIBC_SRCS ${DRLIBC_SRCS} drlibc/drlibc_module_macho.c)
|
||||
else ()
|
||||
set(DRLIBC_SRCS ${DRLIBC_SRCS} drlibc/drlibc_module_elf.c)
|
||||
endif ()
|
||||
endif ()
|
||||
add_gen_events_deps(drhelper)
|
||||
add_library(drlibc STATIC ${DRLIBC_SRCS})
|
||||
# CMake on Windows fails to link unless we tell it to use the C linker:
|
||||
set_target_properties(drlibc PROPERTIES LINKER_LANGUAGE C)
|
||||
if (UNIX)
|
||||
append_property_string(TARGET drlibc COMPILE_FLAGS "-fPIC")
|
||||
endif ()
|
||||
add_gen_events_deps(drlibc)
|
||||
if (AARCH64)
|
||||
add_dependencies(drhelper gen_aarch64_codec)
|
||||
add_dependencies(drlibc gen_aarch64_codec)
|
||||
endif (AARCH64)
|
||||
if (WIN32 AND "${CMAKE_GENERATOR}" MATCHES "Visual Studio")
|
||||
# for parallel build correctness we need a target dependence
|
||||
add_dependencies(drhelper ${shared_core_asm_tgt} ${shared_arch_asm_tgt})
|
||||
add_dependencies(drlibc ${drlibc_xarch_asm_tgt} ${drlibc_arch_asm_tgt})
|
||||
endif ()
|
||||
|
||||
set(CORE_SRCS
|
||||
@@ -201,6 +214,11 @@ if (WIN32 AND NOT X64)
|
||||
set_source_files_properties(utils.c COMPILE_FLAGS "/QIfist")
|
||||
endif (WIN32 AND NOT X64)
|
||||
|
||||
# XXX: Originally we used _shared (inject_shared, etc.) to mean
|
||||
# "shared between multiple libraries", while we've also started using
|
||||
# _shared on opnd_shared.c, etc. to mean 'shared between architectures":
|
||||
# perhaps we should separate the naming schemes. "opnd_xarch.c" and
|
||||
# "inject_xlib.c"?
|
||||
set(DECODER_SRCS
|
||||
arch/opnd_shared.c
|
||||
arch/${ARCH_NAME_SHARED}/opnd.c
|
||||
@@ -349,7 +367,6 @@ if (UNIX)
|
||||
set(PRELOAD_SRCS
|
||||
unix/preload.c
|
||||
config.c
|
||||
unix/os.c
|
||||
# i#1334: private string routines for libc independence
|
||||
string.c
|
||||
io.c
|
||||
@@ -357,7 +374,6 @@ if (UNIX)
|
||||
set(INJECTOR_SRCS
|
||||
unix/injector.c
|
||||
config.c # to read config
|
||||
unix/os.c # for file_t interface
|
||||
string.c
|
||||
io.c
|
||||
)
|
||||
@@ -366,6 +382,7 @@ if (UNIX)
|
||||
else (APPLE)
|
||||
set(INJECTOR_SRCS ${INJECTOR_SRCS} unix/module_elf.c)
|
||||
endif ()
|
||||
|
||||
else (UNIX)
|
||||
set(OSNAME win32)
|
||||
set(OS_SRCS
|
||||
@@ -471,7 +488,7 @@ function (configure_core_lib target)
|
||||
add_dependencies(${target} ${arch_core_asm_tgt} ${archshared_core_asm_tgt})
|
||||
endif ()
|
||||
|
||||
target_link_libraries(${target} drhelper)
|
||||
target_link_libraries(${target} drlibc)
|
||||
copy_target_to_device(${target} "${location_suffix}")
|
||||
|
||||
# rather than a separate BUILD_INCLUDES option we always build
|
||||
@@ -858,7 +875,7 @@ endif()
|
||||
if ("${CMAKE_GENERATOR}" MATCHES "Visual Studio")
|
||||
add_dependencies(${PRELOAD_NAME} ${preinject_asm_tgt})
|
||||
endif ()
|
||||
target_link_libraries(${PRELOAD_NAME} drhelper)
|
||||
target_link_libraries(${PRELOAD_NAME} drlibc)
|
||||
if (UNIX AND X86)
|
||||
# We need our own memcpy + memset for isolation.
|
||||
target_link_libraries(${PRELOAD_NAME} drmemfuncs)
|
||||
@@ -929,7 +946,7 @@ add_gen_events_deps(drdecode)
|
||||
if (AARCH64)
|
||||
add_dependencies(drdecode gen_aarch64_codec)
|
||||
endif()
|
||||
target_link_libraries(drdecode drhelper)
|
||||
target_link_libraries(drdecode drlibc)
|
||||
|
||||
###########################################################################
|
||||
# Injection library
|
||||
@@ -949,7 +966,7 @@ else ()
|
||||
endif ()
|
||||
add_library(drinjectlib ${inject_lib_type} ${INJECTOR_SRCS})
|
||||
add_gen_events_deps(drinjectlib)
|
||||
target_link_libraries(drinjectlib drdecode drhelper)
|
||||
target_link_libraries(drinjectlib drdecode drlibc)
|
||||
if (UNIX AND X86)
|
||||
# We need our own memcpy + memset to avoid glibc versioning (i#1504).
|
||||
target_link_libraries(drinjectlib drmemfuncs)
|
||||
@@ -1036,7 +1053,7 @@ if (BUILD_TESTS)
|
||||
set_target_properties(unit_tests PROPERTIES
|
||||
LINK_FLAGS "/base:${preferred_base} ${LD_FLAGS}")
|
||||
endif (UNIX)
|
||||
target_link_libraries(unit_tests drhelper)
|
||||
target_link_libraries(unit_tests drlibc)
|
||||
get_target_path_for_execution(unit_relpath unit_tests "${location_suffix}")
|
||||
prefix_cmd_if_necessary(unit_relpath OFF ${unit_relpath})
|
||||
add_test(unit_tests ${unit_relpath})
|
||||
@@ -1055,6 +1072,7 @@ include_directories(BEFORE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/arch
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/${OSNAME}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/arch/${ARCH_NAME}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/drlibc
|
||||
)
|
||||
|
||||
# Avoid transitive linking for imported target.
|
||||
@@ -1087,9 +1105,9 @@ endif (UNIX)
|
||||
DR_export_target(drdecode)
|
||||
install_exported_target(drdecode ${INSTALL_LIB})
|
||||
|
||||
# We have to export drhelper as static libs we're exporting depend on it.
|
||||
DR_export_target(drhelper)
|
||||
install_exported_target(drhelper ${INSTALL_LIB_BASE})
|
||||
# We have to export drlibc as static libs we're exporting depend on it.
|
||||
DR_export_target(drlibc)
|
||||
install_exported_target(drlibc ${INSTALL_LIB_BASE})
|
||||
if (UNIX AND X86)
|
||||
DR_export_target(drmemfuncs)
|
||||
install_exported_target(drmemfuncs ${INSTALL_LIB_BASE})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* **********************************************************
|
||||
* Copyright (c) 2015 Google, Inc. All rights reserved.
|
||||
* Copyright (c) 2015-2019 Google, Inc. All rights reserved.
|
||||
* **********************************************************/
|
||||
|
||||
/*
|
||||
@@ -30,7 +30,7 @@
|
||||
* DAMAGE.
|
||||
*/
|
||||
|
||||
/* Default implementation to avoid the user of drhelper having to supply one.
|
||||
/* Default implementation to avoid the user of drlibc having to supply one.
|
||||
* We declare this as weak for Linux and MacOS, and rely on MSVC prioritizing a
|
||||
* .obj def over this .lib def (note that the MSVC linker only does that
|
||||
* when the symbol in question is *by itself* in a single .obj: hence this file,
|
||||
@@ -42,12 +42,52 @@
|
||||
|
||||
#include "../globals.h" /* just to disable warning C4206 about an empty file */
|
||||
|
||||
#ifdef MACOS
|
||||
# include <sys/utsname.h> /* for struct utsname */
|
||||
# include <string.h>
|
||||
#endif
|
||||
|
||||
/***************************************************************************
|
||||
* Compatibility layer for sharing a single compiled-once library
|
||||
* between core and non-core.
|
||||
* Some are separated out into drlibc_notdr_* files since MSVC behaves
|
||||
* better when duplicate symbols are each in their own .obj.
|
||||
*/
|
||||
|
||||
WEAK bool
|
||||
safe_read_if_fast(const void *base, size_t size, void *out_buf)
|
||||
{
|
||||
return safe_read(base, size, out_buf);
|
||||
}
|
||||
|
||||
WEAK void
|
||||
internal_error(const char *file, int line, const char *expr)
|
||||
{
|
||||
/* do nothing by default */
|
||||
/* Do nothing for non-core. */
|
||||
}
|
||||
|
||||
WEAK bool
|
||||
ignore_assert(const char *assert_file_line, const char *expr)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
WEAK file_t main_logfile;
|
||||
WEAK options_t dynamo_options;
|
||||
|
||||
#ifdef MACOS
|
||||
WEAK bool
|
||||
kernel_is_64bit(void)
|
||||
{
|
||||
struct utsname uinfo;
|
||||
if (uname(&uinfo) != 0)
|
||||
return true; /* guess */
|
||||
return (strncmp(uinfo.machine, "x86_64", sizeof("x86_64")) == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
#ifdef AARCH64
|
||||
void
|
||||
clear_icache(void *beg, void *end)
|
||||
@@ -1,5 +1,5 @@
|
||||
/* **********************************************************
|
||||
* Copyright (c) 2011-2015 Google, Inc. All rights reserved.
|
||||
* Copyright (c) 2011-2019 Google, Inc. All rights reserved.
|
||||
* Copyright (c) 2000-2010 VMware, Inc. All rights reserved.
|
||||
* **********************************************************/
|
||||
|
||||
@@ -35,16 +35,16 @@
|
||||
/* Copyright (c) 2001-2003 Massachusetts Institute of Technology */
|
||||
/* Copyright (c) 2000-2001 Hewlett-Packard Company */
|
||||
|
||||
/* header for library of core utilites shared with non-core: "drhelper" */
|
||||
/* header for library of core utilites shared with non-core: "drlibc" */
|
||||
|
||||
#ifndef _DR_HELPER_H_
|
||||
#define _DR_HELPER_H_ 1
|
||||
#ifndef _DR_LIBC_H_
|
||||
#define _DR_LIBC_H_ 1
|
||||
|
||||
/* If the caller is using the DR API they'll have our types that way; else we
|
||||
* include globals_shared.h.
|
||||
*/
|
||||
#ifndef _DR_API_H_
|
||||
# include "globals_shared.h"
|
||||
# include "../lib/globals_shared.h"
|
||||
#endif
|
||||
|
||||
#ifdef UNIX
|
||||
@@ -122,4 +122,4 @@ find_script_interpreter(OUT script_interpreter_t *result, IN const char *fname,
|
||||
ssize_t (*reader)(const char *pathname, void *buf, size_t count));
|
||||
#endif /* UNIX */
|
||||
|
||||
#endif /* _DR_HELPER_H_ */
|
||||
#endif /* _DR_LIBC_H_ */
|
||||
@@ -0,0 +1,523 @@
|
||||
/* *******************************************************************************
|
||||
* Copyright (c) 2012-2019 Google, Inc. All rights reserved.
|
||||
* Copyright (c) 2011 Massachusetts Institute of Technology All rights reserved.
|
||||
* Copyright (c) 2008-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.
|
||||
*/
|
||||
|
||||
/* ELF module analysis routines shared between core and non-core. */
|
||||
|
||||
#include "../globals.h"
|
||||
#include "../module_shared.h"
|
||||
#include "os_private.h"
|
||||
#include "module_private.h"
|
||||
#include "../utils.h"
|
||||
#include "instrument.h"
|
||||
#include <string.h>
|
||||
#include <stddef.h> /* offsetof */
|
||||
#include <link.h> /* Elf_Symndx */
|
||||
|
||||
typedef union _elf_generic_header_t {
|
||||
Elf64_Ehdr elf64;
|
||||
Elf32_Ehdr elf32;
|
||||
} elf_generic_header_t;
|
||||
|
||||
/* This routine is duplicated in privload_mem_is_elf_so_header. Any update here
|
||||
* should be updated in privload_mem_is_elf_so_header.
|
||||
*/
|
||||
/* Is there an ELF header for a shared object at address 'base'?
|
||||
* If size == 0 then checks for header readability else assumes that size bytes from
|
||||
* base are readable (unmap races are then callers responsibility).
|
||||
*/
|
||||
static bool
|
||||
is_elf_so_header_common(app_pc base, size_t size, bool memory)
|
||||
{
|
||||
/* FIXME We could check more fields in the header just as the
|
||||
* dlopen() does. */
|
||||
static const unsigned char ei_expected[SELFMAG] = {
|
||||
[EI_MAG0] = ELFMAG0, [EI_MAG1] = ELFMAG1, [EI_MAG2] = ELFMAG2, [EI_MAG3] = ELFMAG3
|
||||
};
|
||||
ELF_HEADER_TYPE elf_header;
|
||||
|
||||
if (base == NULL) {
|
||||
ASSERT(false && "is_elf_so_header(): NULL base");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Read the header. We used to directly deref if size >= sizeof(ELF_HEADER_TYPE)
|
||||
* but given that we now have safe_read_fast() it's best to always use it and
|
||||
* avoid races (like i#2113). However, the non-fast version hits deadlock on
|
||||
* memquery during client init, so we use a special routine safe_read_if_fast().
|
||||
*/
|
||||
if (size >= sizeof(ELF_HEADER_TYPE)) {
|
||||
if (!safe_read_if_fast(base, sizeof(ELF_HEADER_TYPE), &elf_header))
|
||||
return false;
|
||||
} else if (size == 0) {
|
||||
if (!safe_read(base, sizeof(ELF_HEADER_TYPE), &elf_header))
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* We check the first 4 bytes which is the magic number. */
|
||||
if ((size == 0 || size >= sizeof(ELF_HEADER_TYPE)) &&
|
||||
elf_header.e_ident[EI_MAG0] == ei_expected[EI_MAG0] &&
|
||||
elf_header.e_ident[EI_MAG1] == ei_expected[EI_MAG1] &&
|
||||
elf_header.e_ident[EI_MAG2] == ei_expected[EI_MAG2] &&
|
||||
elf_header.e_ident[EI_MAG3] == ei_expected[EI_MAG3] &&
|
||||
/* PR 475158: if an app loads a linkable but not loadable
|
||||
* file (e.g., .o file) we don't want to treat as a module
|
||||
*/
|
||||
(elf_header.e_type == ET_DYN || elf_header.e_type == ET_EXEC)) {
|
||||
#ifdef CLIENT_INTERFACE
|
||||
/* i#157, we do more check to make sure we load the right modules,
|
||||
* i.e. 32/64-bit libraries.
|
||||
* We check again in privload_map_and_relocate() in loader for nice
|
||||
* error message.
|
||||
* Xref i#1345 for supporting mixed libs, which makes more sense for
|
||||
* standalone mode tools like those using drsyms (i#1532) or
|
||||
* dr_map_executable_file, but we just don't support that yet until we
|
||||
* remove our hardcoded type defines in module_elf.h.
|
||||
*/
|
||||
if ((elf_header.e_version != 1) ||
|
||||
(memory && elf_header.e_ehsize != sizeof(ELF_HEADER_TYPE)) ||
|
||||
(memory &&
|
||||
elf_header.e_machine !=
|
||||
IF_X86_ELSE(IF_X64_ELSE(EM_X86_64, EM_386),
|
||||
IF_X64_ELSE(EM_AARCH64, EM_ARM))))
|
||||
return false;
|
||||
#endif
|
||||
/* FIXME - should we add any of these to the check? For real
|
||||
* modules all of these should hold. */
|
||||
ASSERT_CURIOSITY(elf_header.e_version == 1);
|
||||
ASSERT_CURIOSITY(!memory || elf_header.e_ehsize == sizeof(ELF_HEADER_TYPE));
|
||||
ASSERT_CURIOSITY(elf_header.e_ident[EI_OSABI] == ELFOSABI_SYSV ||
|
||||
elf_header.e_ident[EI_OSABI] == ELFOSABI_LINUX);
|
||||
ASSERT_CURIOSITY(!memory ||
|
||||
elf_header.e_machine ==
|
||||
IF_X86_ELSE(IF_X64_ELSE(EM_X86_64, EM_386),
|
||||
IF_X64_ELSE(EM_AARCH64, EM_ARM)));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* i#727: Recommend passing 0 as size if not known if the header can be safely
|
||||
* read.
|
||||
*/
|
||||
bool
|
||||
is_elf_so_header(app_pc base, size_t size)
|
||||
{
|
||||
return is_elf_so_header_common(base, size, true);
|
||||
}
|
||||
|
||||
uint
|
||||
module_segment_prot_to_osprot(ELF_PROGRAM_HEADER_TYPE *prog_hdr)
|
||||
{
|
||||
uint segment_prot = 0;
|
||||
if (TEST(PF_X, prog_hdr->p_flags))
|
||||
segment_prot |= MEMPROT_EXEC;
|
||||
if (TEST(PF_W, prog_hdr->p_flags))
|
||||
segment_prot |= MEMPROT_WRITE;
|
||||
if (TEST(PF_R, prog_hdr->p_flags))
|
||||
segment_prot |= MEMPROT_READ;
|
||||
return segment_prot;
|
||||
}
|
||||
|
||||
/* XXX: This routine may be called before dynamorio relocation when we are
|
||||
* in a fragile state and thus no globals access or use of ASSERT/LOG/STATS!
|
||||
*/
|
||||
/* Returns the minimum p_vaddr field, aligned to page boundaries, in
|
||||
* the loadable segments in the prog_header array, or POINTER_MAX if
|
||||
* there are no loadable segments.
|
||||
*/
|
||||
app_pc
|
||||
module_vaddr_from_prog_header(app_pc prog_header, uint num_segments,
|
||||
OUT app_pc *out_first_end, OUT app_pc *out_max_end)
|
||||
{
|
||||
uint i;
|
||||
app_pc min_vaddr = (app_pc)POINTER_MAX;
|
||||
app_pc max_end = (app_pc)PTR_UINT_0;
|
||||
app_pc first_end = NULL;
|
||||
for (i = 0; i < num_segments; i++) {
|
||||
/* Without the ELF header we use sizeof instead of elf_hdr->e_phentsize
|
||||
* which must be a reliable assumption as dl_iterate_phdr() doesn't
|
||||
* bother to deliver the entry size.
|
||||
*/
|
||||
ELF_PROGRAM_HEADER_TYPE *prog_hdr =
|
||||
(ELF_PROGRAM_HEADER_TYPE *)(prog_header +
|
||||
i * sizeof(ELF_PROGRAM_HEADER_TYPE));
|
||||
if (prog_hdr->p_type == PT_LOAD) {
|
||||
/* ELF requires p_vaddr to already be aligned to p_align */
|
||||
min_vaddr =
|
||||
MIN(min_vaddr, (app_pc)ALIGN_BACKWARD(prog_hdr->p_vaddr, PAGE_SIZE));
|
||||
if (min_vaddr == (app_pc)prog_hdr->p_vaddr)
|
||||
first_end = (app_pc)prog_hdr->p_vaddr + prog_hdr->p_memsz;
|
||||
max_end = MAX(
|
||||
max_end,
|
||||
(app_pc)ALIGN_FORWARD(prog_hdr->p_vaddr + prog_hdr->p_memsz, PAGE_SIZE));
|
||||
}
|
||||
}
|
||||
if (out_first_end != NULL)
|
||||
*out_first_end = first_end;
|
||||
if (out_max_end != NULL)
|
||||
*out_max_end = max_end;
|
||||
return min_vaddr;
|
||||
}
|
||||
|
||||
bool
|
||||
module_get_platform(file_t f, dr_platform_t *platform, dr_platform_t *alt_platform)
|
||||
{
|
||||
elf_generic_header_t elf_header;
|
||||
if (alt_platform != NULL)
|
||||
*alt_platform = DR_PLATFORM_NONE;
|
||||
if (os_read(f, &elf_header, sizeof(elf_header)) != sizeof(elf_header))
|
||||
return false;
|
||||
if (!is_elf_so_header_common((app_pc)&elf_header, sizeof(elf_header), false))
|
||||
return false;
|
||||
ASSERT(offsetof(Elf64_Ehdr, e_machine) == offsetof(Elf32_Ehdr, e_machine));
|
||||
switch (elf_header.elf64.e_machine) {
|
||||
case EM_X86_64:
|
||||
#ifdef EM_AARCH64
|
||||
case EM_AARCH64:
|
||||
#endif
|
||||
*platform = DR_PLATFORM_64BIT;
|
||||
break;
|
||||
case EM_386:
|
||||
case EM_ARM: *platform = DR_PLATFORM_32BIT; break;
|
||||
default: return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Get the module text section from the mapped image file,
|
||||
* Note that it must be the image file, not the loaded module.
|
||||
*/
|
||||
ELF_ADDR
|
||||
module_get_text_section(app_pc file_map, size_t file_size)
|
||||
{
|
||||
ELF_HEADER_TYPE *elf_hdr = (ELF_HEADER_TYPE *)file_map;
|
||||
ELF_SECTION_HEADER_TYPE *sec_hdr;
|
||||
char *strtab;
|
||||
uint i;
|
||||
ASSERT(is_elf_so_header(file_map, file_size));
|
||||
ASSERT(elf_hdr->e_shoff < file_size);
|
||||
ASSERT(elf_hdr->e_shentsize == sizeof(ELF_SECTION_HEADER_TYPE));
|
||||
ASSERT(elf_hdr->e_shoff + elf_hdr->e_shentsize * elf_hdr->e_shnum <= file_size);
|
||||
sec_hdr = (ELF_SECTION_HEADER_TYPE *)(file_map + elf_hdr->e_shoff);
|
||||
strtab = (char *)(file_map + sec_hdr[elf_hdr->e_shstrndx].sh_offset);
|
||||
for (i = 0; i < elf_hdr->e_shnum; i++) {
|
||||
if (strcmp(".text", strtab + sec_hdr->sh_name) == 0)
|
||||
return sec_hdr->sh_addr;
|
||||
++sec_hdr;
|
||||
}
|
||||
/* ELF doesn't require that there's a section named ".text". */
|
||||
ASSERT_CURIOSITY(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read until EOF or error. Return number of bytes read. */
|
||||
static size_t
|
||||
os_read_until(file_t fd, void *buf, size_t toread)
|
||||
{
|
||||
size_t orig_toread = toread;
|
||||
ssize_t nread;
|
||||
while (toread > 0) {
|
||||
nread = os_read(fd, buf, toread);
|
||||
if (nread <= 0)
|
||||
break;
|
||||
toread -= nread;
|
||||
buf = (app_pc)buf + nread;
|
||||
}
|
||||
return orig_toread - toread;
|
||||
}
|
||||
|
||||
bool
|
||||
elf_loader_init(elf_loader_t *elf, const char *filename)
|
||||
{
|
||||
memset(elf, 0, sizeof(*elf));
|
||||
elf->filename = filename;
|
||||
elf->fd = os_open(filename, OS_OPEN_READ);
|
||||
return elf->fd != INVALID_FILE;
|
||||
}
|
||||
|
||||
void
|
||||
elf_loader_destroy(elf_loader_t *elf)
|
||||
{
|
||||
if (elf->fd != INVALID_FILE) {
|
||||
os_close(elf->fd);
|
||||
}
|
||||
if (elf->file_map != NULL) {
|
||||
os_unmap_file(elf->file_map, elf->file_size);
|
||||
}
|
||||
memset(elf, 0, sizeof(*elf));
|
||||
}
|
||||
|
||||
ELF_HEADER_TYPE *
|
||||
elf_loader_read_ehdr(elf_loader_t *elf)
|
||||
{
|
||||
/* The initial read is sized to read both ehdr and all phdrs. */
|
||||
if (elf->fd == INVALID_FILE)
|
||||
return NULL;
|
||||
if (elf->file_map != NULL) {
|
||||
/* The user mapped the entire file up front, so use it. */
|
||||
elf->ehdr = (ELF_HEADER_TYPE *)elf->file_map;
|
||||
} else {
|
||||
size_t size = os_read_until(elf->fd, elf->buf, sizeof(elf->buf));
|
||||
if (size == 0)
|
||||
return NULL;
|
||||
if (!is_elf_so_header(elf->buf, size))
|
||||
return NULL;
|
||||
elf->ehdr = (ELF_HEADER_TYPE *)elf->buf;
|
||||
}
|
||||
return elf->ehdr;
|
||||
}
|
||||
|
||||
app_pc
|
||||
elf_loader_map_file(elf_loader_t *elf, bool reachable)
|
||||
{
|
||||
uint64 size64;
|
||||
if (elf->file_map != NULL)
|
||||
return elf->file_map;
|
||||
if (elf->fd == INVALID_FILE)
|
||||
return NULL;
|
||||
if (!os_get_file_size_by_handle(elf->fd, &size64))
|
||||
return NULL;
|
||||
ASSERT_TRUNCATE(elf->file_size, size_t, size64);
|
||||
elf->file_size = (size_t)size64; /* truncate */
|
||||
/* We use os_map_file instead of map_file since this mapping is temporary.
|
||||
* We don't need to add and remove it from dynamo_areas.
|
||||
*/
|
||||
elf->file_map =
|
||||
os_map_file(elf->fd, &elf->file_size, 0, NULL, MEMPROT_READ,
|
||||
MAP_FILE_COPY_ON_WRITE | (reachable ? MAP_FILE_REACHABLE : 0));
|
||||
return elf->file_map;
|
||||
}
|
||||
|
||||
ELF_PROGRAM_HEADER_TYPE *
|
||||
elf_loader_read_phdrs(elf_loader_t *elf)
|
||||
{
|
||||
size_t ph_off;
|
||||
size_t ph_size;
|
||||
if (elf->ehdr == NULL)
|
||||
return NULL;
|
||||
ph_off = elf->ehdr->e_phoff;
|
||||
ph_size = elf->ehdr->e_phnum * elf->ehdr->e_phentsize;
|
||||
if (elf->file_map == NULL && ph_off + ph_size < sizeof(elf->buf)) {
|
||||
/* We already read phdrs, and they are in buf. */
|
||||
elf->phdrs = (ELF_PROGRAM_HEADER_TYPE *)(elf->buf + elf->ehdr->e_phoff);
|
||||
} else {
|
||||
/* We have large or distant phdrs, so map the whole file. We could
|
||||
* seek and read just the phdrs to avoid disturbing the address space,
|
||||
* but that would introduce a dependency on DR's heap.
|
||||
*/
|
||||
if (elf_loader_map_file(elf, false /*!reachable*/) == NULL)
|
||||
return NULL;
|
||||
elf->phdrs = (ELF_PROGRAM_HEADER_TYPE *)(elf->file_map + elf->ehdr->e_phoff);
|
||||
}
|
||||
return elf->phdrs;
|
||||
}
|
||||
|
||||
bool
|
||||
elf_loader_read_headers(elf_loader_t *elf, const char *filename)
|
||||
{
|
||||
if (!elf_loader_init(elf, filename))
|
||||
return false;
|
||||
if (elf_loader_read_ehdr(elf) == NULL)
|
||||
return false;
|
||||
if (elf_loader_read_phdrs(elf) == NULL)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
app_pc
|
||||
elf_loader_map_phdrs(elf_loader_t *elf, bool fixed, map_fn_t map_func,
|
||||
unmap_fn_t unmap_func, prot_fn_t prot_func,
|
||||
check_bounds_fn_t check_bounds_func, modload_flags_t flags)
|
||||
{
|
||||
app_pc lib_base, lib_end, last_end;
|
||||
ELF_HEADER_TYPE *elf_hdr = elf->ehdr;
|
||||
app_pc map_base, map_end;
|
||||
reg_t pg_offs;
|
||||
uint seg_prot, i;
|
||||
ptr_int_t delta;
|
||||
size_t initial_map_size;
|
||||
|
||||
ASSERT(elf->phdrs != NULL && "call elf_loader_read_phdrs() first");
|
||||
if (elf->phdrs == NULL)
|
||||
return NULL;
|
||||
|
||||
map_base = module_vaddr_from_prog_header((app_pc)elf->phdrs, elf->ehdr->e_phnum, NULL,
|
||||
&map_end);
|
||||
|
||||
if (fixed && check_bounds_func != NULL)
|
||||
(*check_bounds_func)(elf, map_base, map_end);
|
||||
|
||||
elf->image_size = map_end - map_base;
|
||||
|
||||
/* reserve the memory from os for library */
|
||||
initial_map_size = elf->image_size;
|
||||
if (TEST(MODLOAD_SEPARATE_BSS, flags)) {
|
||||
/* place an extra no-access page after .bss */
|
||||
initial_map_size += PAGE_SIZE;
|
||||
}
|
||||
lib_base = (*map_func)(-1, &initial_map_size, 0, map_base,
|
||||
MEMPROT_NONE, /* so the separating page is no-access */
|
||||
MAP_FILE_COPY_ON_WRITE | MAP_FILE_IMAGE |
|
||||
/* i#1001: a PIE executable may have NULL as preferred
|
||||
* base, in which case the map can be anywhere
|
||||
*/
|
||||
((fixed && map_base != NULL) ? MAP_FILE_FIXED : 0) |
|
||||
(TEST(MODLOAD_REACHABLE, flags) ? MAP_FILE_REACHABLE : 0));
|
||||
ASSERT(lib_base != NULL);
|
||||
if (TEST(MODLOAD_SEPARATE_BSS, flags) && initial_map_size > elf->image_size)
|
||||
elf->image_size = initial_map_size - PAGE_SIZE;
|
||||
else
|
||||
elf->image_size = initial_map_size;
|
||||
lib_end = lib_base + elf->image_size;
|
||||
elf->load_base = lib_base;
|
||||
ASSERT(elf->load_delta == 0 || map_base == NULL);
|
||||
|
||||
if (map_base != NULL && map_base != lib_base) {
|
||||
/* the mapped memory is not at preferred address,
|
||||
* should be ok if it is still reachable for X64,
|
||||
* which will be checked later.
|
||||
*/
|
||||
LOG(GLOBAL, LOG_LOADER, 1, "%s: module not loaded at preferred address\n",
|
||||
__FUNCTION__);
|
||||
}
|
||||
delta = lib_base - map_base;
|
||||
elf->load_delta = delta;
|
||||
|
||||
/* walk over the program header to load the individual segments */
|
||||
last_end = lib_base;
|
||||
for (i = 0; i < elf_hdr->e_phnum; i++) {
|
||||
app_pc seg_base, seg_end, map, file_end;
|
||||
size_t seg_size;
|
||||
ELF_PROGRAM_HEADER_TYPE *prog_hdr =
|
||||
(ELF_PROGRAM_HEADER_TYPE *)((byte *)elf->phdrs + i * elf_hdr->e_phentsize);
|
||||
if (prog_hdr->p_type == PT_LOAD) {
|
||||
bool do_mmap = true;
|
||||
seg_base = (app_pc)ALIGN_BACKWARD(prog_hdr->p_vaddr, PAGE_SIZE) + delta;
|
||||
seg_end =
|
||||
(app_pc)ALIGN_FORWARD(prog_hdr->p_vaddr + prog_hdr->p_filesz, PAGE_SIZE) +
|
||||
delta;
|
||||
seg_size = seg_end - seg_base;
|
||||
if (seg_base != last_end) {
|
||||
/* XXX: a hole, I reserve this space instead of unmap it */
|
||||
size_t hole_size = seg_base - last_end;
|
||||
(*prot_func)(last_end, hole_size, MEMPROT_NONE);
|
||||
}
|
||||
seg_prot = module_segment_prot_to_osprot(prog_hdr);
|
||||
pg_offs = ALIGN_BACKWARD(prog_hdr->p_offset, PAGE_SIZE);
|
||||
if (TEST(MODLOAD_SKIP_WRITABLE, flags) && TEST(MEMPROT_WRITE, seg_prot) &&
|
||||
seg_end == lib_end) {
|
||||
/* We only actually skip if it's the final segment, to allow
|
||||
* unmapping with a single mmap and not worrying about sthg
|
||||
* else having been unmapped at the end in the meantime.
|
||||
*/
|
||||
do_mmap = false;
|
||||
elf->image_size = last_end - lib_base;
|
||||
}
|
||||
/* XXX:
|
||||
* This function can be called after dynamorio_heap_initialized,
|
||||
* and we will use map_file instead of os_map_file.
|
||||
* However, map_file does not allow mmap with overlapped memory,
|
||||
* so we have to unmap the old memory first.
|
||||
* This might be a problem, e.g.
|
||||
* one thread unmaps the memory and before mapping the actual file,
|
||||
* another thread requests memory via mmap takes the memory here,
|
||||
* a racy condition.
|
||||
*/
|
||||
if (seg_size > 0) { /* i#1872: handle empty segments */
|
||||
(*unmap_func)(seg_base, seg_size);
|
||||
if (do_mmap) {
|
||||
map = (*map_func)(
|
||||
elf->fd, &seg_size, pg_offs, seg_base /* base */,
|
||||
seg_prot | MEMPROT_WRITE /* prot */,
|
||||
MAP_FILE_COPY_ON_WRITE /*writes should not change file*/ |
|
||||
MAP_FILE_IMAGE |
|
||||
/* we don't need MAP_FILE_REACHABLE b/c we're fixed */
|
||||
MAP_FILE_FIXED);
|
||||
ASSERT(map != NULL);
|
||||
/* fill zeros at extend size */
|
||||
file_end = (app_pc)prog_hdr->p_vaddr + prog_hdr->p_filesz;
|
||||
if (seg_end > file_end + delta) {
|
||||
if (!TEST(MODLOAD_SEPARATE_PROCESS, flags)) {
|
||||
memset(file_end + delta, 0, seg_end - (file_end + delta));
|
||||
} else {
|
||||
/* FIXME i#37: use a remote memset to zero out this gap or
|
||||
* fix it up in the child. There is typically one RW
|
||||
* PT_LOAD segment for .data and .bss. If .data ends and
|
||||
* .bss starts before filesz bytes, we need to zero the .bss
|
||||
* bytes manually.
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
seg_end =
|
||||
(app_pc)ALIGN_FORWARD(prog_hdr->p_vaddr + prog_hdr->p_memsz, PAGE_SIZE) +
|
||||
delta;
|
||||
seg_size = seg_end - seg_base;
|
||||
if (seg_size > 0 && do_mmap)
|
||||
(*prot_func)(seg_base, seg_size, seg_prot);
|
||||
last_end = seg_end;
|
||||
}
|
||||
}
|
||||
ASSERT(last_end == lib_end);
|
||||
/* FIXME: recover from map failure rather than relying on asserts. */
|
||||
|
||||
return lib_base;
|
||||
}
|
||||
|
||||
/* Iterate program headers of a mapped ELF image and find the string that
|
||||
* PT_INTERP points to. Typically this comes early in the file and is always
|
||||
* included in PT_LOAD segments, so we safely do this after the initial
|
||||
* mapping.
|
||||
*/
|
||||
const char *
|
||||
elf_loader_find_pt_interp(elf_loader_t *elf)
|
||||
{
|
||||
int i;
|
||||
ELF_HEADER_TYPE *ehdr = elf->ehdr;
|
||||
ELF_PROGRAM_HEADER_TYPE *phdrs = elf->phdrs;
|
||||
|
||||
ASSERT(elf->load_base != NULL && "call elf_loader_map_phdrs() first");
|
||||
if (ehdr == NULL || phdrs == NULL || elf->load_base == NULL)
|
||||
return NULL;
|
||||
for (i = 0; i < ehdr->e_phnum; i++) {
|
||||
if (phdrs[i].p_type == PT_INTERP) {
|
||||
return (const char *)(phdrs[i].p_vaddr + elf->load_delta);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
/* *******************************************************************************
|
||||
* Copyright (c) 2013-2019 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 GOOGLE, 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.
|
||||
*/
|
||||
|
||||
/* Mach-O file parsing support shared with non-core. */
|
||||
|
||||
#include "../globals.h"
|
||||
#include "../module_shared.h"
|
||||
#include "os_private.h"
|
||||
#include "module_private.h"
|
||||
#include "memquery_macos.h"
|
||||
#include "module_macos_dyld.h"
|
||||
#include <mach-o/ldsyms.h> /* _mh_dylib_header */
|
||||
#include <mach-o/loader.h> /* mach_header */
|
||||
#include <mach-o/dyld_images.h>
|
||||
#include <mach/thread_status.h> /* i386_thread_state_t */
|
||||
#include <mach-o/nlist.h>
|
||||
#include <mach-o/fat.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <stddef.h> /* offsetof */
|
||||
#include <string.h> /* strcmp */
|
||||
#include <dlfcn.h>
|
||||
|
||||
/* Like is_elf_so_header(), if size == 0 then safe-reads the header; else
|
||||
* assumes that [base, base+size) is readable.
|
||||
*/
|
||||
bool
|
||||
is_macho_header(app_pc base, size_t size)
|
||||
{
|
||||
struct mach_header hdr_safe;
|
||||
struct mach_header *hdr;
|
||||
if (base == NULL)
|
||||
return false;
|
||||
if (size >= sizeof(hdr_safe)) {
|
||||
hdr = (struct mach_header *)base;
|
||||
} else {
|
||||
if (!safe_read(base, sizeof(hdr_safe), &hdr_safe))
|
||||
return false;
|
||||
hdr = &hdr_safe;
|
||||
}
|
||||
ASSERT(offsetof(struct mach_header, filetype) ==
|
||||
offsetof(struct mach_header_64, filetype));
|
||||
if ((hdr->magic == MH_MAGIC && hdr->cputype == CPU_TYPE_X86) ||
|
||||
(hdr->magic == MH_MAGIC_64 && hdr->cputype == CPU_TYPE_X86_64)) {
|
||||
/* We shouldn't see MH_PRELOAD as it can't be loaded by the kernel */
|
||||
if (hdr->filetype == MH_EXECUTE || hdr->filetype == MH_DYLIB ||
|
||||
hdr->filetype == MH_BUNDLE || hdr->filetype == MH_DYLINKER ||
|
||||
hdr->filetype == MH_FVMLIB) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
platform_from_macho(file_t f, dr_platform_t *platform)
|
||||
{
|
||||
struct mach_header mach_hdr;
|
||||
if (os_read(f, &mach_hdr, sizeof(mach_hdr)) != sizeof(mach_hdr))
|
||||
return false;
|
||||
if (!is_macho_header((app_pc)&mach_hdr, sizeof(mach_hdr)))
|
||||
return false;
|
||||
switch (mach_hdr.cputype) {
|
||||
case CPU_TYPE_X86_64: *platform = DR_PLATFORM_64BIT; break;
|
||||
case CPU_TYPE_X86: *platform = DR_PLATFORM_32BIT; break;
|
||||
default: return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
module_get_platform(file_t f, dr_platform_t *platform, dr_platform_t *alt_platform)
|
||||
{
|
||||
struct fat_header fat_hdr;
|
||||
/* Both headers start with a 32-bit magic # */
|
||||
uint32_t magic;
|
||||
if (os_read(f, &magic, sizeof(magic)) != sizeof(magic) || !os_seek(f, 0, SEEK_SET))
|
||||
return false;
|
||||
if (magic == FAT_CIGAM) { /* big-endian */
|
||||
/* This is a "fat" or "universal" binary */
|
||||
struct fat_arch arch;
|
||||
uint num, i;
|
||||
bool found_main = false, found_alt = false;
|
||||
dr_platform_t local_alt = DR_PLATFORM_NONE;
|
||||
int64 cur_pos;
|
||||
if (os_read(f, &fat_hdr, sizeof(fat_hdr)) != sizeof(fat_hdr))
|
||||
return false;
|
||||
/* OSSwapInt32 is a macro, so there's no lib dependence here */
|
||||
num = OSSwapInt32(fat_hdr.nfat_arch);
|
||||
for (i = 0; i < num; i++) {
|
||||
if (os_read(f, &arch, sizeof(arch)) != sizeof(arch))
|
||||
return false;
|
||||
cur_pos = os_tell(f);
|
||||
/* The primary platform is the one that will be used on an execve,
|
||||
* which is the one that matches the kernel's bitwidth.
|
||||
*/
|
||||
if ((kernel_is_64bit() && OSSwapInt32(arch.cputype) == CPU_TYPE_X86_64) ||
|
||||
(!kernel_is_64bit() && OSSwapInt32(arch.cputype) == CPU_TYPE_X86)) {
|
||||
/* Line up right before the Mach-O header */
|
||||
if (!os_seek(f, OSSwapInt32(arch.offset), SEEK_SET))
|
||||
return false;
|
||||
if (!platform_from_macho(f, platform))
|
||||
return false;
|
||||
found_main = true;
|
||||
if (found_alt)
|
||||
break;
|
||||
} else if (OSSwapInt32(arch.cputype) == CPU_TYPE_X86_64 ||
|
||||
OSSwapInt32(arch.cputype) == CPU_TYPE_X86) {
|
||||
/* Line up right before the Mach-O header */
|
||||
if (!os_seek(f, OSSwapInt32(arch.offset), SEEK_SET))
|
||||
return false;
|
||||
if (platform_from_macho(f, &local_alt)) {
|
||||
found_alt = true;
|
||||
if (found_main)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!os_seek(f, cur_pos, SEEK_SET))
|
||||
return false;
|
||||
}
|
||||
if (!found_main && found_alt) {
|
||||
*platform = local_alt;
|
||||
local_alt = DR_PLATFORM_NONE;
|
||||
}
|
||||
if (alt_platform != NULL)
|
||||
*alt_platform = local_alt;
|
||||
return (found_main || found_alt);
|
||||
} else if (alt_platform != NULL)
|
||||
*alt_platform = DR_PLATFORM_NONE;
|
||||
return platform_from_macho(f, platform);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/* **********************************************************
|
||||
* Copyright (c) 2019 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 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.
|
||||
*/
|
||||
|
||||
/* Default implementation to avoid the user of drlibc having to supply one.
|
||||
* We need to separate these as the MSVC linker will not complain about duplicate
|
||||
* symbols if an .obj has just one symbol in it.
|
||||
*/
|
||||
|
||||
#define DR_NO_FAST_IR /* Avoid pulling in deps from instr_inline.h from globals.h */
|
||||
#include "../globals.h"
|
||||
|
||||
WEAK dcontext_t *
|
||||
get_thread_private_dcontext(void)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/* **********************************************************
|
||||
* Copyright (c) 2019 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 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.
|
||||
*/
|
||||
|
||||
/* Default implementation to avoid the user of drlibc having to supply one.
|
||||
* We need to separate these as the MSVC linker will not complain about duplicate
|
||||
* symbols if an .obj has just one symbol in it.
|
||||
*/
|
||||
|
||||
#define DR_NO_FAST_IR /* Avoid pulling in deps from instr_inline.h from globals.h */
|
||||
#include "../globals.h"
|
||||
|
||||
WEAK file_t
|
||||
get_thread_private_logfile(void)
|
||||
{
|
||||
return INVALID_FILE;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/* **********************************************************
|
||||
* Copyright (c) 2019 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 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.
|
||||
*/
|
||||
|
||||
/* Default implementation to avoid the user of drlibc having to supply one.
|
||||
* We need to separate these as the MSVC linker will not complain about duplicate
|
||||
* symbols if an .obj has just one symbol in it.
|
||||
*/
|
||||
|
||||
#define DR_NO_FAST_IR /* Avoid pulling in deps from instr_inline.h from globals.h */
|
||||
#include "../globals.h"
|
||||
|
||||
WEAK void
|
||||
print_log(file_t logfile, uint mask, uint level, const char *fmt, ...)
|
||||
{
|
||||
/* Do nothing for non-core. */
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/* **********************************************************
|
||||
* Copyright (c) 2019 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 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.
|
||||
*/
|
||||
|
||||
/* Default implementation to avoid the user of drlibc having to supply one.
|
||||
* We need to separate these as the MSVC linker will not complain about duplicate
|
||||
* symbols if an .obj has just one symbol in it.
|
||||
*/
|
||||
|
||||
#define DR_NO_FAST_IR /* Avoid pulling in deps from instr_inline.h from globals.h */
|
||||
#include "../globals.h"
|
||||
|
||||
WEAK void
|
||||
report_dynamorio_problem(dcontext_t *dcontext, uint dumpcore_flag, app_pc exception_addr,
|
||||
app_pc report_ebp, const char *fmt, ...)
|
||||
{
|
||||
/* Do nothing for non-core. */
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/* **********************************************************
|
||||
* Copyright (c) 2019 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 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.
|
||||
*/
|
||||
|
||||
/* Default implementation to avoid the user of drlibc having to supply one.
|
||||
* We need to separate these as the MSVC linker will not complain about duplicate
|
||||
* symbols if an .obj has just one symbol in it.
|
||||
*/
|
||||
|
||||
#define DR_NO_FAST_IR /* Avoid pulling in deps from instr_inline.h from globals.h */
|
||||
#include "../globals.h"
|
||||
|
||||
WEAK bool
|
||||
safe_read(const void *base, size_t size, void *out_buf)
|
||||
{
|
||||
memcpy(out_buf, base, size);
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/* **********************************************************
|
||||
* Copyright (c) 2019 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 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.
|
||||
*/
|
||||
|
||||
/* Default implementation to avoid the user of drlibc having to supply one.
|
||||
* We need to separate these as the MSVC linker will not complain about duplicate
|
||||
* symbols if an .obj has just one symbol in it.
|
||||
*/
|
||||
|
||||
#define DR_NO_FAST_IR /* Avoid pulling in deps from instr_inline.h from globals.h */
|
||||
#include "../globals.h"
|
||||
|
||||
static dr_statistics_t libmodule_stats;
|
||||
WEAK dr_statistics_t *stats = &libmodule_stats;
|
||||
@@ -0,0 +1,609 @@
|
||||
/* *******************************************************************************
|
||||
* Copyright (c) 2010-2019 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.
|
||||
*/
|
||||
|
||||
/* Copyright (c) 2003-2007 Determina Corp. */
|
||||
/* Copyright (c) 2001-2003 Massachusetts Institute of Technology */
|
||||
/* Copyright (c) 2000-2001 Hewlett-Packard Company */
|
||||
|
||||
/*
|
||||
* os.c - Linux specific routines
|
||||
*/
|
||||
|
||||
/* See os.c comment on why we define this. */
|
||||
#define _LARGEFILE64_SOURCE
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
/* Avoid pulling in deps from instr_inline.h included from globals.h */
|
||||
#define DR_NO_FAST_IR
|
||||
#include "../globals.h"
|
||||
|
||||
#ifdef LINUX
|
||||
# include "include/syscall.h" /* our own local copy */
|
||||
#else
|
||||
# include <sys/syscall.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
/* Just like in os.c we avoid the errno variable. */
|
||||
#if !defined(STANDALONE_UNIT_TEST) && !defined(MACOS)
|
||||
# undef errno
|
||||
#endif
|
||||
|
||||
/* XXX: We've moved this code out of core/unix but we're still including a private
|
||||
* header from there. We should try to separate the headers a little better
|
||||
* to make this a more isolated library.
|
||||
*/
|
||||
#include "os_private.h"
|
||||
|
||||
#ifdef LINUX
|
||||
# include "module_private.h" /* for ELF_AUXV_TYPE and AT_PAGESZ */
|
||||
#endif
|
||||
|
||||
process_id_t
|
||||
get_process_id()
|
||||
{
|
||||
return dynamorio_syscall(SYS_getpid, 0);
|
||||
}
|
||||
|
||||
/* translate permission string to platform independent protection bits */
|
||||
uint
|
||||
permstr_to_memprot(const char *const perm)
|
||||
{
|
||||
uint mem_prot = 0;
|
||||
if (perm == NULL || *perm == '\0')
|
||||
return mem_prot;
|
||||
if (perm[2] == 'x')
|
||||
mem_prot |= MEMPROT_EXEC;
|
||||
if (perm[1] == 'w')
|
||||
mem_prot |= MEMPROT_WRITE;
|
||||
if (perm[0] == 'r')
|
||||
mem_prot |= MEMPROT_READ;
|
||||
return mem_prot;
|
||||
}
|
||||
|
||||
/* translate platform independent protection bits to native flags */
|
||||
uint
|
||||
memprot_to_osprot(uint prot)
|
||||
{
|
||||
uint mmap_prot = 0;
|
||||
if (TEST(MEMPROT_EXEC, prot))
|
||||
mmap_prot |= PROT_EXEC;
|
||||
if (TEST(MEMPROT_READ, prot))
|
||||
mmap_prot |= PROT_READ;
|
||||
if (TEST(MEMPROT_WRITE, prot))
|
||||
mmap_prot |= PROT_WRITE;
|
||||
return mmap_prot;
|
||||
}
|
||||
|
||||
bool
|
||||
mmap_syscall_succeeded(byte *retval)
|
||||
{
|
||||
ptr_int_t result = (ptr_int_t)retval;
|
||||
/* libc interprets up to -PAGE_SIZE as an error, and you never know if
|
||||
* some weird errno will be used by say vmkernel (xref PR 365331)
|
||||
*/
|
||||
bool fail = (result < 0 && result >= -PAGE_SIZE);
|
||||
ASSERT_CURIOSITY(!fail ||
|
||||
IF_VMX86(result == -ENOENT ||) IF_VMX86(result == -ENOSPC ||)
|
||||
result == -EBADF ||
|
||||
result == -EACCES || result == -EINVAL || result == -ETXTBSY ||
|
||||
result == -EAGAIN || result == -ENOMEM || result == -ENODEV ||
|
||||
result == -EFAULT || result == -EPERM);
|
||||
return !fail;
|
||||
}
|
||||
|
||||
/* N.B.: offs should be in pages for 32-bit Linux */
|
||||
byte *
|
||||
mmap_syscall(byte *addr, size_t len, ulong prot, ulong flags, ulong fd, ulong offs)
|
||||
{
|
||||
#if defined(MACOS) && !defined(X64)
|
||||
return (byte *)(ptr_int_t)dynamorio_syscall(
|
||||
SYS_mmap, 7, addr, len, prot, flags, fd,
|
||||
/* represent 64-bit arg as 2 32-bit args */
|
||||
offs, 0);
|
||||
#else
|
||||
return (byte *)(ptr_int_t)dynamorio_syscall(
|
||||
IF_MACOS_ELSE(SYS_mmap, IF_X64_ELSE(SYS_mmap, SYS_mmap2)), 6, addr, len, prot,
|
||||
flags, fd, offs);
|
||||
#endif
|
||||
}
|
||||
|
||||
long
|
||||
munmap_syscall(byte *addr, size_t len)
|
||||
{
|
||||
return dynamorio_syscall(SYS_munmap, 2, addr, len);
|
||||
}
|
||||
|
||||
/* FIXME - not available in 2.0 or earlier kernels, not really an issue since no one
|
||||
* should be running anything that old. */
|
||||
static int
|
||||
llseek_syscall(int fd, int64 offset, int origin, int64 *result)
|
||||
{
|
||||
#if defined(X64) || defined(MACOS)
|
||||
# ifndef X64
|
||||
/* 2 slots for 64-bit arg */
|
||||
*result = dynamorio_syscall(SYS_lseek, 4, fd, (uint)(offset & 0xFFFFFFFF),
|
||||
(uint)((offset >> 32) & 0xFFFFFFFF), origin);
|
||||
# else
|
||||
*result = dynamorio_syscall(SYS_lseek, 3, fd, offset, origin);
|
||||
# endif
|
||||
return ((*result > 0) ? 0 : (int)*result);
|
||||
#else
|
||||
return dynamorio_syscall(SYS__llseek, 5, fd, (uint)((offset >> 32) & 0xFFFFFFFF),
|
||||
(uint)(offset & 0xFFFFFFFF), result, origin);
|
||||
#endif
|
||||
}
|
||||
|
||||
static ptr_int_t
|
||||
dynamorio_syscall_stat(const char *fname, struct stat64 *st)
|
||||
{
|
||||
#ifdef SYSNUM_STAT
|
||||
return dynamorio_syscall(SYSNUM_STAT, 2, fname, st);
|
||||
#else
|
||||
return dynamorio_syscall(SYS_fstatat, 4, AT_FDCWD, fname, st, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
os_file_exists(const char *fname, bool is_dir)
|
||||
{
|
||||
/* _LARGEFILE64_SOURCE should make libc struct match kernel (see top of file) */
|
||||
struct stat64 st;
|
||||
ptr_int_t res = dynamorio_syscall_stat(fname, &st);
|
||||
if (res != 0) {
|
||||
LOG(THREAD_GET, LOG_SYSCALLS, 2, "%s failed: " PIFX "\n", __func__, res);
|
||||
return false;
|
||||
}
|
||||
return (!is_dir || S_ISDIR(st.st_mode));
|
||||
}
|
||||
|
||||
/* Returns true if two paths point to the same file. Follows symlinks.
|
||||
*/
|
||||
bool
|
||||
os_files_same(const char *path1, const char *path2)
|
||||
{
|
||||
struct stat64 st1, st2;
|
||||
ptr_int_t res = dynamorio_syscall_stat(path1, &st1);
|
||||
if (res != 0) {
|
||||
LOG(THREAD_GET, LOG_SYSCALLS, 2, "%s failed: " PIFX "\n", __func__, res);
|
||||
return false;
|
||||
}
|
||||
res = dynamorio_syscall_stat(path2, &st2);
|
||||
if (res != 0) {
|
||||
LOG(THREAD_GET, LOG_SYSCALLS, 2, "%s failed: " PIFX "\n", __func__, res);
|
||||
return false;
|
||||
}
|
||||
return st1.st_ino == st2.st_ino;
|
||||
}
|
||||
|
||||
bool
|
||||
os_get_file_size(const char *file, uint64 *size)
|
||||
{
|
||||
/* _LARGEFILE64_SOURCE should make libc struct match kernel (see top of file) */
|
||||
struct stat64 st;
|
||||
ptr_int_t res = dynamorio_syscall_stat(file, &st);
|
||||
if (res != 0) {
|
||||
LOG(THREAD_GET, LOG_SYSCALLS, 2, "%s failed: " PIFX "\n", __func__, res);
|
||||
return false;
|
||||
}
|
||||
ASSERT(size != NULL);
|
||||
*size = st.st_size;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
os_get_file_size_by_handle(file_t fd, uint64 *size)
|
||||
{
|
||||
/* _LARGEFILE64_SOURCE should make libc struct match kernel (see top of file) */
|
||||
struct stat64 st;
|
||||
ptr_int_t res = dynamorio_syscall(SYSNUM_FSTAT, 2, fd, &st);
|
||||
if (res != 0) {
|
||||
LOG(THREAD_GET, LOG_SYSCALLS, 2, "%s failed: " PIFX "\n", __func__, res);
|
||||
return false;
|
||||
}
|
||||
ASSERT(size != NULL);
|
||||
*size = st.st_size;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* created directory will be owned by effective uid,
|
||||
* Note a symbolic link will never be followed.
|
||||
*/
|
||||
bool
|
||||
os_create_dir(const char *fname, create_directory_flags_t create_dir_flags)
|
||||
{
|
||||
bool require_new = TEST(CREATE_DIR_REQUIRE_NEW, create_dir_flags);
|
||||
#ifdef SYS_mkdir
|
||||
int rc = dynamorio_syscall(SYS_mkdir, 2, fname, S_IRWXU | S_IRWXG);
|
||||
#else
|
||||
int rc = dynamorio_syscall(SYS_mkdirat, 3, AT_FDCWD, fname, S_IRWXU | S_IRWXG);
|
||||
#endif
|
||||
ASSERT(create_dir_flags == CREATE_DIR_REQUIRE_NEW ||
|
||||
create_dir_flags == CREATE_DIR_ALLOW_EXISTING);
|
||||
return (rc == 0 || (!require_new && rc == -EEXIST));
|
||||
}
|
||||
|
||||
bool
|
||||
os_delete_dir(const char *name)
|
||||
{
|
||||
#ifdef SYS_rmdir
|
||||
return (dynamorio_syscall(SYS_rmdir, 1, name) == 0);
|
||||
#else
|
||||
return (dynamorio_syscall(SYS_unlinkat, 3, AT_FDCWD, name, AT_REMOVEDIR) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
open_syscall(const char *file, int flags, int mode)
|
||||
{
|
||||
ASSERT(file != NULL);
|
||||
#ifdef SYS_open
|
||||
return dynamorio_syscall(SYSNUM_NO_CANCEL(SYS_open), 3, file, flags, mode);
|
||||
#else
|
||||
return dynamorio_syscall(SYSNUM_NO_CANCEL(SYS_openat), 4, AT_FDCWD, file, flags,
|
||||
mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
close_syscall(int fd)
|
||||
{
|
||||
return dynamorio_syscall(SYSNUM_NO_CANCEL(SYS_close), 1, fd);
|
||||
}
|
||||
|
||||
int
|
||||
dup_syscall(int fd)
|
||||
{
|
||||
return dynamorio_syscall(SYS_dup, 1, fd);
|
||||
}
|
||||
|
||||
ssize_t
|
||||
read_syscall(int fd, void *buf, size_t nbytes)
|
||||
{
|
||||
return dynamorio_syscall(SYSNUM_NO_CANCEL(SYS_read), 3, fd, buf, nbytes);
|
||||
}
|
||||
|
||||
ssize_t
|
||||
write_syscall(int fd, const void *buf, size_t nbytes)
|
||||
{
|
||||
return dynamorio_syscall(SYSNUM_NO_CANCEL(SYS_write), 3, fd, buf, nbytes);
|
||||
}
|
||||
|
||||
/* not easily accessible in header files */
|
||||
#ifndef O_LARGEFILE
|
||||
# ifdef X64
|
||||
/* not needed */
|
||||
# define O_LARGEFILE 0
|
||||
# else
|
||||
# define O_LARGEFILE 0100000
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* we assume that opening for writing wants to create file.
|
||||
* we also assume that nobody calling this is creating a persistent
|
||||
* file: for that, use os_open_protected() to avoid leaking on exec
|
||||
* and to separate from the app's files.
|
||||
*/
|
||||
file_t
|
||||
os_open(const char *fname, int os_open_flags)
|
||||
{
|
||||
int res;
|
||||
int flags = 0;
|
||||
if (TEST(OS_OPEN_ALLOW_LARGE, os_open_flags))
|
||||
flags |= O_LARGEFILE;
|
||||
if (TEST(OS_OPEN_WRITE_ONLY, os_open_flags))
|
||||
res = open_syscall(fname, flags | O_WRONLY, 0);
|
||||
else if (!TEST(OS_OPEN_WRITE, os_open_flags))
|
||||
res = open_syscall(fname, flags | O_RDONLY, 0);
|
||||
else {
|
||||
res = open_syscall(
|
||||
fname,
|
||||
flags | O_RDWR | O_CREAT |
|
||||
(TEST(OS_OPEN_APPEND, os_open_flags)
|
||||
?
|
||||
/* Currently we only support either appending
|
||||
* or truncating, just like Windows and the client
|
||||
* interface. If we end up w/ a use case that wants
|
||||
* neither it could open append and then seek; if we do
|
||||
* add OS_TRUNCATE or sthg we'll need to add it to
|
||||
* any current writers who don't set OS_OPEN_REQUIRE_NEW.
|
||||
*/
|
||||
O_APPEND
|
||||
: O_TRUNC) |
|
||||
(TEST(OS_OPEN_REQUIRE_NEW, os_open_flags) ? O_EXCL : 0),
|
||||
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
|
||||
}
|
||||
if (res < 0)
|
||||
return INVALID_FILE;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
file_t
|
||||
os_open_directory(const char *fname, int os_open_flags)
|
||||
{
|
||||
/* no special handling */
|
||||
return os_open(fname, os_open_flags);
|
||||
}
|
||||
|
||||
void
|
||||
os_close(file_t f)
|
||||
{
|
||||
close_syscall(f);
|
||||
}
|
||||
|
||||
/* no os_write() so drinject can use drdecode's copy */
|
||||
|
||||
ssize_t
|
||||
os_read(file_t f, void *buf, size_t count)
|
||||
{
|
||||
return read_syscall(f, buf, count);
|
||||
}
|
||||
|
||||
void
|
||||
os_flush(file_t f)
|
||||
{
|
||||
/* we're not using FILE*, so there is no buffering */
|
||||
}
|
||||
|
||||
/* seek current file position to offset bytes from origin, return true if successful */
|
||||
bool
|
||||
os_seek(file_t f, int64 offset, int origin)
|
||||
{
|
||||
int64 result;
|
||||
int ret = 0;
|
||||
|
||||
ret = llseek_syscall(f, offset, origin, &result);
|
||||
|
||||
return (ret == 0);
|
||||
}
|
||||
|
||||
/* return the current file position, -1 on failure */
|
||||
int64
|
||||
os_tell(file_t f)
|
||||
{
|
||||
int64 result = -1;
|
||||
int ret = 0;
|
||||
|
||||
ret = llseek_syscall(f, 0, SEEK_CUR, &result);
|
||||
|
||||
if (ret != 0)
|
||||
return -1;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
os_delete_file(const char *name)
|
||||
{
|
||||
#ifdef SYS_unlink
|
||||
return (dynamorio_syscall(SYS_unlink, 1, name) == 0);
|
||||
#else
|
||||
return (dynamorio_syscall(SYS_unlinkat, 3, AT_FDCWD, name, 0) == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
os_rename_file(const char *orig_name, const char *new_name, bool replace)
|
||||
{
|
||||
ptr_int_t res;
|
||||
if (!replace) {
|
||||
/* SYS_rename replaces so we must test beforehand => could have race */
|
||||
/* _LARGEFILE64_SOURCE should make libc struct match kernel (see top of file) */
|
||||
struct stat64 st;
|
||||
ptr_int_t res = dynamorio_syscall_stat(new_name, &st);
|
||||
if (res == 0)
|
||||
return false;
|
||||
else if (res != -ENOENT) {
|
||||
LOG(THREAD_GET, LOG_SYSCALLS, 2, "%s stat failed: " PIFX "\n", __func__, res);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#ifdef SYS_rename
|
||||
res = dynamorio_syscall(SYS_rename, 2, orig_name, new_name);
|
||||
#else
|
||||
res = dynamorio_syscall(SYS_renameat, 4, AT_FDCWD, orig_name, AT_FDCWD, new_name);
|
||||
#endif
|
||||
if (res != 0) {
|
||||
LOG(THREAD_GET, LOG_SYSCALLS, 2, "%s \"%s\" to \"%s\" failed: " PIFX "\n",
|
||||
__func__, orig_name, new_name, res);
|
||||
}
|
||||
return (res == 0);
|
||||
}
|
||||
|
||||
bool
|
||||
os_delete_mapped_file(const char *filename)
|
||||
{
|
||||
return os_delete_file(filename);
|
||||
}
|
||||
|
||||
/* We mark as weak so the core can override with its more complex version. */
|
||||
WEAK byte *
|
||||
os_map_file(file_t f, size_t *size INOUT, uint64 offs, app_pc addr, uint prot,
|
||||
map_flags_t map_flags)
|
||||
{
|
||||
int flags;
|
||||
byte *map;
|
||||
uint pg_offs;
|
||||
ASSERT_TRUNCATE(pg_offs, uint, offs / PAGE_SIZE);
|
||||
pg_offs = (uint)(offs / PAGE_SIZE);
|
||||
#ifdef VMX86_SERVER
|
||||
flags = MAP_PRIVATE; /* MAP_SHARED not supported yet */
|
||||
#else
|
||||
flags = TEST(MAP_FILE_COPY_ON_WRITE, map_flags) ? MAP_PRIVATE : MAP_SHARED;
|
||||
#endif
|
||||
/* Allows memory request instead of mapping a file,
|
||||
* so we can request memory from a particular address with fixed argument */
|
||||
if (f == -1)
|
||||
flags |= MAP_ANONYMOUS;
|
||||
if (TEST(MAP_FILE_FIXED, map_flags))
|
||||
flags |= MAP_FIXED;
|
||||
map = mmap_syscall(addr, *size, memprot_to_osprot(prot), flags, f,
|
||||
/* x86 Linux mmap uses offset in pages */
|
||||
IF_LINUX_ELSE(IF_X64_ELSE(offs, pg_offs), offs));
|
||||
if (!mmap_syscall_succeeded(map)) {
|
||||
LOG(THREAD_GET, LOG_SYSCALLS, 2, "%s failed: " PIFX "\n", __func__, map);
|
||||
map = NULL;
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
bool
|
||||
os_unmap_file(byte *map, size_t size)
|
||||
{
|
||||
long res = munmap_syscall(map, size);
|
||||
return (res == 0);
|
||||
}
|
||||
|
||||
const reg_id_t syscall_regparms[MAX_SYSCALL_ARGS] = {
|
||||
#ifdef X86
|
||||
# ifdef X64
|
||||
DR_REG_RDI, DR_REG_RSI,
|
||||
DR_REG_RDX, DR_REG_R10, /* RCX goes here in normal x64 calling contention. */
|
||||
DR_REG_R8, DR_REG_R9
|
||||
# else
|
||||
DR_REG_EBX, DR_REG_ECX, DR_REG_EDX, DR_REG_ESI, DR_REG_EDI, DR_REG_EBP
|
||||
# endif /* 64/32-bit */
|
||||
#elif defined(AARCHXX)
|
||||
DR_REG_R0, DR_REG_R1, DR_REG_R2, DR_REG_R3, DR_REG_R4, DR_REG_R5,
|
||||
#endif /* X86/ARM */
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* Page size discovery and query
|
||||
*/
|
||||
|
||||
/* This variable is only used by os_set_page_size and os_page_size, but those
|
||||
* functions may be called before libdynamorio.so has been relocated. So check
|
||||
* the disassembly of those functions: there should be no relocations.
|
||||
*/
|
||||
static size_t page_size = 0;
|
||||
|
||||
/* Return true if size is a multiple of the page size.
|
||||
* XXX: This function may be called when DynamoRIO is in a fragile state, or not
|
||||
* yet relocated, so keep this self-contained and do not use global variables or
|
||||
* logging.
|
||||
*/
|
||||
static bool
|
||||
os_try_page_size(size_t size)
|
||||
{
|
||||
byte *addr =
|
||||
mmap_syscall(NULL, size * 2, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if ((ptr_uint_t)addr >= (ptr_uint_t)-4096) /* mmap failed: should not happen */
|
||||
return false;
|
||||
if (munmap_syscall(addr + size, size) == 0) {
|
||||
/* munmap of top half succeeded: munmap bottom half and return true */
|
||||
munmap_syscall(addr, size);
|
||||
return true;
|
||||
}
|
||||
/* munmap of top half failed: munmap whole region and return false */
|
||||
munmap_syscall(addr, size * 2);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Directly determine the granularity of memory allocation using mmap and munmap.
|
||||
* This is used as a last resort if the page size is required before it has been
|
||||
* discovered in any other way, such as from AT_PAGESZ.
|
||||
* XXX: This function may be called when DynamoRIO is in a fragile state, or not
|
||||
* yet relocated, so keep this self-contained and do not use global variables or
|
||||
* logging.
|
||||
*/
|
||||
static size_t
|
||||
os_find_page_size(void)
|
||||
{
|
||||
size_t size = 4096;
|
||||
if (os_try_page_size(size)) {
|
||||
/* Try smaller sizes. */
|
||||
for (size /= 2; size > 0; size /= 2) {
|
||||
if (!os_try_page_size(size))
|
||||
return size * 2;
|
||||
}
|
||||
} else {
|
||||
/* Try larger sizes. */
|
||||
for (size *= 2; size * 2 > 0; size *= 2) {
|
||||
if (os_try_page_size(size))
|
||||
return size;
|
||||
}
|
||||
}
|
||||
/* Something went wrong... */
|
||||
return 4096;
|
||||
}
|
||||
|
||||
static void
|
||||
os_set_page_size(size_t size)
|
||||
{
|
||||
page_size = size; /* atomic write */
|
||||
}
|
||||
|
||||
size_t
|
||||
os_page_size(void)
|
||||
{
|
||||
size_t size = page_size; /* atomic read */
|
||||
if (size == 0) {
|
||||
/* XXX: On Mac OSX we should use sysctl_query on hw.pagesize. */
|
||||
size = os_find_page_size();
|
||||
os_set_page_size(size);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
void
|
||||
os_page_size_init(const char **env)
|
||||
{
|
||||
#if defined(LINUX) && !defined(STATIC_LIBRARY)
|
||||
/* On Linux we get the page size from the auxiliary vector, which is what
|
||||
* the C library typically does for implementing sysconf(_SC_PAGESIZE).
|
||||
* However, for STATIC_LIBRARY, our_environ is not guaranteed to point
|
||||
* at the stack as we're so late, so we do not try to read off the end of it
|
||||
* (i#2122).
|
||||
*/
|
||||
size_t size = page_size; /* atomic read */
|
||||
if (size == 0) {
|
||||
ELF_AUXV_TYPE *auxv;
|
||||
/* Skip environment. */
|
||||
while (*env != 0)
|
||||
++env;
|
||||
/* Look for AT_PAGESZ in the auxiliary vector. */
|
||||
for (auxv = (ELF_AUXV_TYPE *)(env + 1); auxv->a_type != AT_NULL; auxv++) {
|
||||
if (auxv->a_type == AT_PAGESZ) {
|
||||
os_set_page_size(auxv->a_un.a_val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* LINUX */
|
||||
}
|
||||
@@ -571,7 +571,7 @@ smc_return_to_32:
|
||||
|
||||
/****************************************************************************
|
||||
* Injection code shared between core and drinjectlib.
|
||||
* XXX: since we are exporting this file in the "drhelper" lib we may want
|
||||
* XXX: since we are exporting this file in the "drlibc" lib we may want
|
||||
* to should move this code to a new file inject_shared.asm or sthg.
|
||||
*/
|
||||
#ifdef WINDOWS
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/* **********************************************************
|
||||
* Copyright (c) 2011-2018 Google, Inc. All rights reserved.
|
||||
* Copyright (c) 2011-2019 Google, Inc. All rights reserved.
|
||||
* Copyright (c) 2000-2010 VMware, Inc. All rights reserved.
|
||||
* **********************************************************/
|
||||
|
||||
@@ -346,7 +346,7 @@ typedef struct _thread_record_t {
|
||||
#include "options.h"
|
||||
#include "os_exports.h"
|
||||
#include "arch_exports.h"
|
||||
#include "dr_helper.h"
|
||||
#include "drlibc.h"
|
||||
#include "vmareas.h"
|
||||
#include "instrlist.h"
|
||||
#include "dispatch.h"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* **********************************************************
|
||||
* Copyright (c) 2011-2016 Google, Inc. All rights reserved.
|
||||
* Copyright (c) 2011-2019 Google, Inc. All rights reserved.
|
||||
* Copyright (c) 2008-2010 VMware, Inc. All rights reserved.
|
||||
* **********************************************************/
|
||||
|
||||
@@ -536,6 +536,12 @@ typedef enum {
|
||||
/* These are for use with dr_map_executable_file(): */
|
||||
MODLOAD_NOT_PRIVLIB = 0x0002,
|
||||
MODLOAD_SKIP_WRITABLE = 0x0004, /* ignored on Windows */
|
||||
/* For use with privload_map_and_relocate() or elf_loader_map_phdrs().
|
||||
* Places an extra no-access page after .bss.
|
||||
*/
|
||||
MODLOAD_SEPARATE_BSS = 0x0008,
|
||||
/* Indicates that the module is being loaded in another process. */
|
||||
MODLOAD_SEPARATE_PROCESS = 0x0010,
|
||||
} modload_flags_t;
|
||||
|
||||
/* This function is used for loading non-private libs as well as private. */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* **********************************************************
|
||||
* Copyright (c) 2012-2018 Google, Inc. All rights reserved.
|
||||
* Copyright (c) 2012-2019 Google, Inc. All rights reserved.
|
||||
* **********************************************************/
|
||||
|
||||
/*
|
||||
@@ -1430,7 +1430,8 @@ inject_ptrace(dr_inject_info_t *info, const char *library_path)
|
||||
injector_dr_fd = loader.fd;
|
||||
injectee_dr_fd = dr_fd;
|
||||
injected_base = elf_loader_map_phdrs(&loader, true /*fixed*/, injectee_map_file,
|
||||
injectee_unmap, injectee_prot, 0 /*!reachable*/);
|
||||
injectee_unmap, injectee_prot, NULL,
|
||||
MODLOAD_SEPARATE_PROCESS /*!reachable*/);
|
||||
if (injected_base == NULL) {
|
||||
if (verbose)
|
||||
fprintf(stderr, "Unable to mmap libdynamorio.so in injectee\n");
|
||||
|
||||
+38
-9
@@ -1,5 +1,5 @@
|
||||
/* *******************************************************************************
|
||||
* Copyright (c) 2011-2018 Google, Inc. All rights reserved.
|
||||
* Copyright (c) 2011-2019 Google, Inc. All rights reserved.
|
||||
* Copyright (c) 2011 Massachusetts Institute of Technology All rights reserved.
|
||||
* *******************************************************************************/
|
||||
|
||||
@@ -425,6 +425,33 @@ privload_unload_imports(privmod_t *privmod)
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef LINUX
|
||||
/* Core-specific functionality for elf_loader_map_phdrs(). */
|
||||
static modload_flags_t
|
||||
privload_map_flags(modload_flags_t init_flags)
|
||||
{
|
||||
if (INTERNAL_OPTION(separate_private_bss) && !TEST(MODLOAD_NOT_PRIVLIB, init_flags)) {
|
||||
/* place an extra no-access page after .bss */
|
||||
/* XXX: update privload_early_inject call to init_emulated_brk if this changes */
|
||||
/* XXX: should we avoid this for -early_inject's map of the app and ld.so? */
|
||||
return init_flags | MODLOAD_SEPARATE_BSS;
|
||||
}
|
||||
return init_flags;
|
||||
}
|
||||
|
||||
/* Core-specific functionality for elf_loader_map_phdrs(). */
|
||||
static void
|
||||
privload_check_new_map_bounds(elf_loader_t *elf, byte *map_base, byte *map_end)
|
||||
{
|
||||
/* This is only called for MAP_FIXED. */
|
||||
if (get_dynamorio_dll_start() < map_end && get_dynamorio_dll_end() > map_base) {
|
||||
FATAL_USAGE_ERROR(FIXED_MAP_OVERLAPS_DR, 3, get_application_name(),
|
||||
get_application_pid(), elf->filename);
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* This only maps, as relocation for ELF requires processing imports first,
|
||||
* which we have to delay at init time at least.
|
||||
*/
|
||||
@@ -468,9 +495,9 @@ privload_map_and_relocate(const char *filename, size_t *size OUT, modload_flags_
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
base = elf_loader_map_phdrs(&loader, false /* fixed */, map_func, unmap_func,
|
||||
prot_func, flags);
|
||||
base =
|
||||
elf_loader_map_phdrs(&loader, false /* fixed */, map_func, unmap_func, prot_func,
|
||||
privload_check_new_map_bounds, privload_map_flags(flags));
|
||||
if (base != NULL) {
|
||||
if (size != NULL)
|
||||
*size = loader.image_size;
|
||||
@@ -1698,7 +1725,8 @@ reload_dynamorio(void **init_sp, app_pc conflict_start, app_pc conflict_end)
|
||||
|
||||
/* Now load the 2nd libdynamorio.so */
|
||||
dr_map = elf_loader_map_phdrs(&dr_ld, false /*!fixed*/, os_map_file, os_unmap_file,
|
||||
os_set_protection, 0 /*!reachable*/);
|
||||
os_set_protection, privload_check_new_map_bounds,
|
||||
privload_map_flags(0 /*!reachable*/));
|
||||
ASSERT(dr_map != NULL);
|
||||
ASSERT(is_elf_so_header(dr_map, 0));
|
||||
|
||||
@@ -1843,7 +1871,8 @@ privload_early_inject(void **sp, byte *old_libdr_base, size_t old_libdr_size)
|
||||
true,
|
||||
/* ensure there's space for the brk */
|
||||
map_exe_file_and_brk, os_unmap_file, os_set_protection,
|
||||
0 /*!reachable*/);
|
||||
privload_check_new_map_bounds,
|
||||
privload_map_flags(0 /*!reachable*/));
|
||||
apicheck(exe_map != NULL,
|
||||
"Failed to load application. "
|
||||
"Check path and architecture.");
|
||||
@@ -1887,9 +1916,9 @@ privload_early_inject(void **sp, byte *old_libdr_base, size_t old_libdr_size)
|
||||
elf_loader_t interp_ld;
|
||||
success = elf_loader_read_headers(&interp_ld, interp);
|
||||
apicheck(success, "Failed to read ELF interpreter headers.");
|
||||
interp_map =
|
||||
elf_loader_map_phdrs(&interp_ld, false /* fixed */, os_map_file,
|
||||
os_unmap_file, os_set_protection, 0 /*!reachable*/);
|
||||
interp_map = elf_loader_map_phdrs(
|
||||
&interp_ld, false /* fixed */, os_map_file, os_unmap_file, os_set_protection,
|
||||
privload_check_new_map_bounds, privload_map_flags(0 /*!reachable*/));
|
||||
apicheck(interp_map != NULL && is_elf_so_header(interp_map, 0),
|
||||
"Failed to map ELF interpreter.");
|
||||
/* On Android, the system loader /system/bin/linker sets itself
|
||||
|
||||
+1
-6
@@ -1,5 +1,5 @@
|
||||
/* **********************************************************
|
||||
* Copyright (c) 2011-2018 Google, Inc. All rights reserved.
|
||||
* Copyright (c) 2011-2019 Google, Inc. All rights reserved.
|
||||
* Copyright (c) 2008-2010 VMware, Inc. All rights reserved.
|
||||
* **********************************************************/
|
||||
|
||||
@@ -196,11 +196,6 @@ get_private_library_address(app_pc modbase, const char *name);
|
||||
bool
|
||||
get_private_library_bounds(IN app_pc modbase, OUT byte **start, OUT byte **end);
|
||||
|
||||
typedef byte *(*map_fn_t)(file_t f, size_t *size INOUT, uint64 offs, app_pc addr,
|
||||
uint prot /*MEMPROT_*/, map_flags_t map_flags);
|
||||
typedef bool (*unmap_fn_t)(byte *map, size_t size);
|
||||
typedef bool (*prot_fn_t)(byte *map, size_t size, uint prot /*MEMPROT_*/);
|
||||
|
||||
#ifdef MACOS
|
||||
/* module_macho.c */
|
||||
byte *
|
||||
|
||||
+30
-563
@@ -1,5 +1,5 @@
|
||||
/* *******************************************************************************
|
||||
* Copyright (c) 2012-2018 Google, Inc. All rights reserved.
|
||||
* Copyright (c) 2012-2019 Google, Inc. All rights reserved.
|
||||
* Copyright (c) 2011 Massachusetts Institute of Technology All rights reserved.
|
||||
* Copyright (c) 2008-2010 VMware, Inc. All rights reserved.
|
||||
* *******************************************************************************/
|
||||
@@ -42,11 +42,6 @@
|
||||
#include <stddef.h> /* offsetof */
|
||||
#include <link.h> /* Elf_Symndx */
|
||||
|
||||
typedef union _elf_generic_header_t {
|
||||
Elf64_Ehdr elf64;
|
||||
Elf32_Ehdr elf32;
|
||||
} elf_generic_header_t;
|
||||
|
||||
#ifndef ANDROID
|
||||
struct tlsdesc_t {
|
||||
ptr_int_t (*entry)(struct tlsdesc_t *);
|
||||
@@ -66,35 +61,7 @@ typedef uint32_t Elf_Symndx;
|
||||
# define STN_UNDEF 0
|
||||
#endif
|
||||
|
||||
#ifdef NOT_DYNAMORIO_CORE_PROPER
|
||||
# undef LOG
|
||||
# define LOG(...) /* nothing */
|
||||
# undef ASSERT
|
||||
# define ASSERT(x) ((void)0)
|
||||
# undef ASSERT_NOT_IMPLEMENTED
|
||||
# define ASSERT_NOT_IMPLEMENTED(x) ((void)0)
|
||||
# undef ASSERT_CURIOSITY
|
||||
# define ASSERT_CURIOSITY(x) ((void)0)
|
||||
|
||||
/* Compatibility layer
|
||||
* XXX i#1409: really we should split out a lib shared w/ non-core from os.c.
|
||||
*/
|
||||
bool
|
||||
safe_read(const void *base, size_t size, void *out_buf)
|
||||
{
|
||||
memcpy(out_buf, base, size);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
safe_read_if_fast(const void *base, size_t size, void *out_buf)
|
||||
{
|
||||
return safe_read(base, size, out_buf);
|
||||
}
|
||||
|
||||
#else /* !NOT_DYNAMORIO_CORE_PROPER */
|
||||
|
||||
# ifdef CLIENT_INTERFACE
|
||||
#ifdef CLIENT_INTERFACE
|
||||
typedef struct _elf_symbol_iterator_t {
|
||||
dr_symbol_import_t symbol_import; /* symbol import returned by next() */
|
||||
dr_symbol_export_t symbol_export; /* symbol export returned by next() */
|
||||
@@ -122,16 +89,16 @@ typedef struct _elf_symbol_iterator_t {
|
||||
Elf_Symndx hidx;
|
||||
Elf_Symndx chain_idx;
|
||||
} elf_symbol_iterator_t;
|
||||
# endif /* CLIENT_INTERFACE */
|
||||
#endif /* CLIENT_INTERFACE */
|
||||
|
||||
/* In case want to build w/o gnu headers and use that to run recent gnu elf */
|
||||
# ifndef DT_GNU_HASH
|
||||
# define DT_GNU_HASH 0x6ffffef5
|
||||
# endif
|
||||
#ifndef DT_GNU_HASH
|
||||
# define DT_GNU_HASH 0x6ffffef5
|
||||
#endif
|
||||
|
||||
# ifndef STT_GNU_IFUNC
|
||||
# define STT_GNU_IFUNC STT_LOOS
|
||||
# endif
|
||||
#ifndef STT_GNU_IFUNC
|
||||
# define STT_GNU_IFUNC STT_LOOS
|
||||
#endif
|
||||
|
||||
/* forward declaration */
|
||||
static void
|
||||
@@ -153,97 +120,6 @@ module_hashtab_init(os_module_data_t *os_data);
|
||||
* etc.
|
||||
*/
|
||||
|
||||
#endif /* !NOT_DYNAMORIO_CORE_PROPER */
|
||||
|
||||
/* This routine is duplicated in privload_mem_is_elf_so_header. Any update here
|
||||
* should be updated in privload_mem_is_elf_so_header.
|
||||
*/
|
||||
/* Is there an ELF header for a shared object at address 'base'?
|
||||
* If size == 0 then checks for header readability else assumes that size bytes from
|
||||
* base are readable (unmap races are then callers responsibility).
|
||||
*/
|
||||
static bool
|
||||
is_elf_so_header_common(app_pc base, size_t size, bool memory)
|
||||
{
|
||||
/* FIXME We could check more fields in the header just as the
|
||||
* dlopen() does. */
|
||||
static const unsigned char ei_expected[SELFMAG] = {
|
||||
[EI_MAG0] = ELFMAG0, [EI_MAG1] = ELFMAG1, [EI_MAG2] = ELFMAG2, [EI_MAG3] = ELFMAG3
|
||||
};
|
||||
ELF_HEADER_TYPE elf_header;
|
||||
|
||||
if (base == NULL) {
|
||||
ASSERT(false && "is_elf_so_header(): NULL base");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Read the header. We used to directly deref if size >= sizeof(ELF_HEADER_TYPE)
|
||||
* but given that we now have safe_read_fast() it's best to always use it and
|
||||
* avoid races (like i#2113). However, the non-fast version hits deadlock on
|
||||
* memquery during client init, so we use a special routine safe_read_if_fast().
|
||||
*/
|
||||
if (size >= sizeof(ELF_HEADER_TYPE)) {
|
||||
if (!safe_read_if_fast(base, sizeof(ELF_HEADER_TYPE), &elf_header))
|
||||
return false;
|
||||
} else if (size == 0) {
|
||||
if (!safe_read(base, sizeof(ELF_HEADER_TYPE), &elf_header))
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* We check the first 4 bytes which is the magic number. */
|
||||
if ((size == 0 || size >= sizeof(ELF_HEADER_TYPE)) &&
|
||||
elf_header.e_ident[EI_MAG0] == ei_expected[EI_MAG0] &&
|
||||
elf_header.e_ident[EI_MAG1] == ei_expected[EI_MAG1] &&
|
||||
elf_header.e_ident[EI_MAG2] == ei_expected[EI_MAG2] &&
|
||||
elf_header.e_ident[EI_MAG3] == ei_expected[EI_MAG3] &&
|
||||
/* PR 475158: if an app loads a linkable but not loadable
|
||||
* file (e.g., .o file) we don't want to treat as a module
|
||||
*/
|
||||
(elf_header.e_type == ET_DYN || elf_header.e_type == ET_EXEC)) {
|
||||
#ifdef CLIENT_INTERFACE
|
||||
/* i#157, we do more check to make sure we load the right modules,
|
||||
* i.e. 32/64-bit libraries.
|
||||
* We check again in privload_map_and_relocate() in loader for nice
|
||||
* error message.
|
||||
* Xref i#1345 for supporting mixed libs, which makes more sense for
|
||||
* standalone mode tools like those using drsyms (i#1532) or
|
||||
* dr_map_executable_file, but we just don't support that yet until we
|
||||
* remove our hardcoded type defines in module_elf.h.
|
||||
*/
|
||||
if ((elf_header.e_version != 1) ||
|
||||
(memory && elf_header.e_ehsize != sizeof(ELF_HEADER_TYPE)) ||
|
||||
(memory &&
|
||||
elf_header.e_machine !=
|
||||
IF_X86_ELSE(IF_X64_ELSE(EM_X86_64, EM_386),
|
||||
IF_X64_ELSE(EM_AARCH64, EM_ARM))))
|
||||
return false;
|
||||
#endif
|
||||
/* FIXME - should we add any of these to the check? For real
|
||||
* modules all of these should hold. */
|
||||
ASSERT_CURIOSITY(elf_header.e_version == 1);
|
||||
ASSERT_CURIOSITY(!memory || elf_header.e_ehsize == sizeof(ELF_HEADER_TYPE));
|
||||
ASSERT_CURIOSITY(elf_header.e_ident[EI_OSABI] == ELFOSABI_SYSV ||
|
||||
elf_header.e_ident[EI_OSABI] == ELFOSABI_LINUX);
|
||||
ASSERT_CURIOSITY(!memory ||
|
||||
elf_header.e_machine ==
|
||||
IF_X86_ELSE(IF_X64_ELSE(EM_X86_64, EM_386),
|
||||
IF_X64_ELSE(EM_AARCH64, EM_ARM)));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* i#727: Recommend passing 0 as size if not known if the header can be safely
|
||||
* read.
|
||||
*/
|
||||
bool
|
||||
is_elf_so_header(app_pc base, size_t size)
|
||||
{
|
||||
return is_elf_so_header_common(base, size, true);
|
||||
}
|
||||
|
||||
bool
|
||||
module_file_has_module_header(const char *filename)
|
||||
{
|
||||
@@ -295,8 +171,6 @@ module_is_partial_map(app_pc base, size_t size, uint memprot)
|
||||
ALIGN_FORWARD(size, PAGE_SIZE) < (last_seg_end - first_seg_base);
|
||||
}
|
||||
|
||||
#ifndef NOT_DYNAMORIO_CORE_PROPER
|
||||
|
||||
/* Returns absolute address of the ELF dynamic array DT_ target */
|
||||
static app_pc
|
||||
elf_dt_abs_addr(ELF_DYNAMIC_ENTRY_TYPE *dyn, app_pc base, size_t size, size_t view_size,
|
||||
@@ -336,23 +210,6 @@ elf_dt_abs_addr(ELF_DYNAMIC_ENTRY_TYPE *dyn, app_pc base, size_t size, size_t vi
|
||||
return tgt;
|
||||
}
|
||||
|
||||
#endif /* !NOT_DYNAMORIO_CORE_PROPER */
|
||||
|
||||
uint
|
||||
module_segment_prot_to_osprot(ELF_PROGRAM_HEADER_TYPE *prog_hdr)
|
||||
{
|
||||
uint segment_prot = 0;
|
||||
if (TEST(PF_X, prog_hdr->p_flags))
|
||||
segment_prot |= MEMPROT_EXEC;
|
||||
if (TEST(PF_W, prog_hdr->p_flags))
|
||||
segment_prot |= MEMPROT_WRITE;
|
||||
if (TEST(PF_R, prog_hdr->p_flags))
|
||||
segment_prot |= MEMPROT_READ;
|
||||
return segment_prot;
|
||||
}
|
||||
|
||||
#ifndef NOT_DYNAMORIO_CORE_PROPER
|
||||
|
||||
/* common code to fill os_module_data_t for loader and module_area_t */
|
||||
static bool
|
||||
module_fill_os_data(ELF_PROGRAM_HEADER_TYPE *prog_hdr, /* PT_DYNAMIC entry */
|
||||
@@ -378,7 +235,7 @@ module_fill_os_data(ELF_PROGRAM_HEADER_TYPE *prog_hdr, /* PT_DYNAMIC entry */
|
||||
dcontext_t *dcontext = get_thread_private_dcontext();
|
||||
/* i#489, DT_SONAME is optional, init soname to NULL first */
|
||||
*soname = NULL;
|
||||
# ifdef ANDROID
|
||||
#ifdef ANDROID
|
||||
/* On Android only the first segment is mapped in and .dynamic is not
|
||||
* accessible. We try to avoid the cost of the fault.
|
||||
* If we do a query (e.g., via is_readable_without_exception()) we'll get
|
||||
@@ -389,7 +246,7 @@ module_fill_os_data(ELF_PROGRAM_HEADER_TYPE *prog_hdr, /* PT_DYNAMIC entry */
|
||||
*/
|
||||
if ((app_pc)dyn > base + view_size)
|
||||
return false;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
TRY_EXCEPT_ALLOW_NO_DCONTEXT(
|
||||
dcontext,
|
||||
@@ -429,12 +286,12 @@ module_fill_os_data(ELF_PROGRAM_HEADER_TYPE *prog_hdr, /* PT_DYNAMIC entry */
|
||||
out_data->symentry_size = (size_t)dyn->d_un.d_val;
|
||||
} else if (dyn->d_tag == DT_RUNPATH) {
|
||||
out_data->has_runpath = true;
|
||||
# ifndef ANDROID
|
||||
#ifndef ANDROID
|
||||
} else if (dyn->d_tag == DT_CHECKSUM) {
|
||||
out_data->checksum = (size_t)dyn->d_un.d_val;
|
||||
} else if (dyn->d_tag == DT_GNU_PRELINKED) {
|
||||
out_data->timestamp = (size_t)dyn->d_un.d_val;
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
dyn++;
|
||||
@@ -614,50 +471,6 @@ os_module_update_dynamic_info(app_pc base, size_t size, bool at_map)
|
||||
}
|
||||
os_get_module_info_write_unlock();
|
||||
}
|
||||
#endif /* !NOT_DYNAMORIO_CORE_PROPER */
|
||||
|
||||
/* XXX: This routine may be called before dynamorio relocation when we are
|
||||
* in a fragile state and thus no globals access or use of ASSERT/LOG/STATS!
|
||||
*/
|
||||
/* Returns the minimum p_vaddr field, aligned to page boundaries, in
|
||||
* the loadable segments in the prog_header array, or POINTER_MAX if
|
||||
* there are no loadable segments.
|
||||
*/
|
||||
app_pc
|
||||
module_vaddr_from_prog_header(app_pc prog_header, uint num_segments,
|
||||
OUT app_pc *out_first_end, OUT app_pc *out_max_end)
|
||||
{
|
||||
uint i;
|
||||
app_pc min_vaddr = (app_pc)POINTER_MAX;
|
||||
app_pc max_end = (app_pc)PTR_UINT_0;
|
||||
app_pc first_end = NULL;
|
||||
for (i = 0; i < num_segments; i++) {
|
||||
/* Without the ELF header we use sizeof instead of elf_hdr->e_phentsize
|
||||
* which must be a reliable assumption as dl_iterate_phdr() doesn't
|
||||
* bother to deliver the entry size.
|
||||
*/
|
||||
ELF_PROGRAM_HEADER_TYPE *prog_hdr =
|
||||
(ELF_PROGRAM_HEADER_TYPE *)(prog_header +
|
||||
i * sizeof(ELF_PROGRAM_HEADER_TYPE));
|
||||
if (prog_hdr->p_type == PT_LOAD) {
|
||||
/* ELF requires p_vaddr to already be aligned to p_align */
|
||||
min_vaddr =
|
||||
MIN(min_vaddr, (app_pc)ALIGN_BACKWARD(prog_hdr->p_vaddr, PAGE_SIZE));
|
||||
if (min_vaddr == (app_pc)prog_hdr->p_vaddr)
|
||||
first_end = (app_pc)prog_hdr->p_vaddr + prog_hdr->p_memsz;
|
||||
max_end = MAX(
|
||||
max_end,
|
||||
(app_pc)ALIGN_FORWARD(prog_hdr->p_vaddr + prog_hdr->p_memsz, PAGE_SIZE));
|
||||
}
|
||||
}
|
||||
if (out_first_end != NULL)
|
||||
*out_first_end = first_end;
|
||||
if (out_max_end != NULL)
|
||||
*out_max_end = max_end;
|
||||
return min_vaddr;
|
||||
}
|
||||
|
||||
#ifndef NOT_DYNAMORIO_CORE_PROPER
|
||||
|
||||
bool
|
||||
module_read_program_header(app_pc base, uint segment_num,
|
||||
@@ -942,13 +755,11 @@ get_proc_address(module_base_t lib, const char *name)
|
||||
return get_proc_address_ex(lib, name, NULL);
|
||||
}
|
||||
|
||||
#endif /* !NOT_DYNAMORIO_CORE_PROPER */
|
||||
|
||||
size_t
|
||||
module_get_header_size(app_pc module_base)
|
||||
{
|
||||
ELF_HEADER_TYPE *elf_header = (ELF_HEADER_TYPE *)module_base;
|
||||
if (!is_elf_so_header_common(module_base, 0, true))
|
||||
if (!is_elf_so_header(module_base, 0))
|
||||
return 0;
|
||||
ASSERT(offsetof(Elf64_Ehdr, e_machine) == offsetof(Elf32_Ehdr, e_machine));
|
||||
if (elf_header->e_machine == EM_X86_64)
|
||||
@@ -957,33 +768,6 @@ module_get_header_size(app_pc module_base)
|
||||
return sizeof(Elf32_Ehdr);
|
||||
}
|
||||
|
||||
bool
|
||||
module_get_platform(file_t f, dr_platform_t *platform, dr_platform_t *alt_platform)
|
||||
{
|
||||
elf_generic_header_t elf_header;
|
||||
if (alt_platform != NULL)
|
||||
*alt_platform = DR_PLATFORM_NONE;
|
||||
if (os_read(f, &elf_header, sizeof(elf_header)) != sizeof(elf_header))
|
||||
return false;
|
||||
if (!is_elf_so_header_common((app_pc)&elf_header, sizeof(elf_header), false))
|
||||
return false;
|
||||
ASSERT(offsetof(Elf64_Ehdr, e_machine) == offsetof(Elf32_Ehdr, e_machine));
|
||||
switch (elf_header.elf64.e_machine) {
|
||||
case EM_X86_64:
|
||||
#ifdef EM_AARCH64
|
||||
case EM_AARCH64:
|
||||
#endif
|
||||
*platform = DR_PLATFORM_64BIT;
|
||||
break;
|
||||
case EM_386:
|
||||
case EM_ARM: *platform = DR_PLATFORM_32BIT; break;
|
||||
default: return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef NOT_DYNAMORIO_CORE_PROPER
|
||||
|
||||
/* returns true if the module is marked as having text relocations.
|
||||
* XXX: should we also have a routine that walks the relocs (once that
|
||||
* code is in) and really checks whether there are any text
|
||||
@@ -1331,7 +1115,7 @@ module_undef_symbols()
|
||||
FATAL_USAGE_ERROR(UNDEFINED_SYMBOL_REFERENCE, 0, "");
|
||||
}
|
||||
|
||||
# ifdef CLIENT_INTERFACE
|
||||
#ifdef CLIENT_INTERFACE
|
||||
|
||||
static ELF_SYM_TYPE *
|
||||
symbol_iterator_cur_symbol(elf_symbol_iterator_t *iter)
|
||||
@@ -1573,15 +1357,15 @@ dr_symbol_export_iterator_stop(dr_symbol_export_iterator_t *dr_iter)
|
||||
symbol_iterator_stop((elf_symbol_iterator_t *)dr_iter);
|
||||
}
|
||||
|
||||
# endif /* CLIENT_INTERFACE */
|
||||
#endif /* CLIENT_INTERFACE */
|
||||
|
||||
# ifndef ANDROID
|
||||
#ifndef ANDROID
|
||||
|
||||
# ifdef AARCH64
|
||||
# ifdef AARCH64
|
||||
/* Defined in aarch64.asm. */
|
||||
ptr_int_t
|
||||
tlsdesc_resolver(struct tlsdesc_t *);
|
||||
# else
|
||||
# else
|
||||
static ptr_int_t
|
||||
tlsdesc_resolver(struct tlsdesc_t *arg)
|
||||
{
|
||||
@@ -1589,9 +1373,9 @@ tlsdesc_resolver(struct tlsdesc_t *arg)
|
||||
ASSERT_NOT_IMPLEMENTED(false);
|
||||
return 0;
|
||||
}
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# endif /* !ANDROID */
|
||||
#endif /* !ANDROID */
|
||||
|
||||
/* This routine is duplicated in privload_relocate_symbol for relocating
|
||||
* dynamorio symbols in a bootstrap stage. Any update here should be also
|
||||
@@ -1641,10 +1425,10 @@ module_relocate_symbol(ELF_REL_TYPE *rel, os_privmod_data_t *pd, bool is_rela)
|
||||
sym = &((ELF_SYM_TYPE *)pd->os_data.dynsym)[r_sym];
|
||||
name = (char *)pd->os_data.dynstr + sym->st_name;
|
||||
|
||||
# ifdef CLIENT_INTERFACE
|
||||
#ifdef CLIENT_INTERFACE
|
||||
if (INTERNAL_OPTION(private_loader) && privload_redirect_sym(r_addr, name))
|
||||
return;
|
||||
# endif
|
||||
#endif
|
||||
|
||||
resolved = true;
|
||||
/* handle syms that do not need symbol lookup */
|
||||
@@ -1666,7 +1450,7 @@ module_relocate_symbol(ELF_REL_TYPE *rel, os_privmod_data_t *pd, bool is_rela)
|
||||
if (sym != NULL)
|
||||
*r_addr = sym->st_value + addend;
|
||||
break;
|
||||
# ifndef ANDROID
|
||||
#ifndef ANDROID
|
||||
case ELF_R_TLS_DESC: {
|
||||
/* Provided the client does not invoke dr_load_aux_library after the
|
||||
* app has started and might have called clone, TLS descriptors can be
|
||||
@@ -1678,19 +1462,19 @@ module_relocate_symbol(ELF_REL_TYPE *rel, os_privmod_data_t *pd, bool is_rela)
|
||||
tlsdesc->arg = (void *)(sym->st_value + addend - pd->tls_offset);
|
||||
break;
|
||||
}
|
||||
# ifndef X64
|
||||
# ifndef X64
|
||||
case R_386_TLS_TPOFF32:
|
||||
/* offset is positive, backward from the thread pointer */
|
||||
if (sym != NULL)
|
||||
*r_addr += pd->tls_offset - sym->st_value;
|
||||
break;
|
||||
# endif
|
||||
# endif
|
||||
case ELF_R_IRELATIVE:
|
||||
res = (byte *)pd->load_delta + (is_rela ? addend : *r_addr);
|
||||
*r_addr = ((ELF_ADDR(*)(void))res)();
|
||||
LOG(GLOBAL, LOG_LOADER, 4, "privmod ifunc reloc %s => " PFX "\n", name, *r_addr);
|
||||
break;
|
||||
# endif /* ANDROID */
|
||||
#endif /* ANDROID */
|
||||
default: resolved = false;
|
||||
}
|
||||
if (resolved)
|
||||
@@ -1723,18 +1507,18 @@ module_relocate_symbol(ELF_REL_TYPE *rel, os_privmod_data_t *pd, bool is_rela)
|
||||
if (sym != NULL)
|
||||
memcpy(r_addr, res, sym->st_size);
|
||||
break;
|
||||
# ifdef X86
|
||||
#ifdef X86
|
||||
case ELF_R_PC32:
|
||||
res += addend - (reg_t)r_addr;
|
||||
*(uint *)r_addr = (uint)(reg_t)res;
|
||||
break;
|
||||
# ifdef X64
|
||||
# ifdef X64
|
||||
case R_X86_64_32:
|
||||
res += addend;
|
||||
*(uint *)r_addr = (uint)(reg_t)res;
|
||||
break;
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
/* FIXME i#1551: add ARM specific relocs type handling */
|
||||
default:
|
||||
/* unhandled rel type */
|
||||
@@ -1770,320 +1554,3 @@ module_relocate_rela(app_pc modbase, os_privmod_data_t *pd, ELF_RELA_TYPE *start
|
||||
for (rela = start; rela < end; rela++)
|
||||
module_relocate_symbol((ELF_REL_TYPE *)rela, pd, true);
|
||||
}
|
||||
|
||||
#endif /* !NOT_DYNAMORIO_CORE_PROPER */
|
||||
|
||||
/* Get the module text section from the mapped image file,
|
||||
* Note that it must be the image file, not the loaded module.
|
||||
*/
|
||||
ELF_ADDR
|
||||
module_get_text_section(app_pc file_map, size_t file_size)
|
||||
{
|
||||
ELF_HEADER_TYPE *elf_hdr = (ELF_HEADER_TYPE *)file_map;
|
||||
ELF_SECTION_HEADER_TYPE *sec_hdr;
|
||||
char *strtab;
|
||||
uint i;
|
||||
ASSERT(is_elf_so_header(file_map, file_size));
|
||||
ASSERT(elf_hdr->e_shoff < file_size);
|
||||
ASSERT(elf_hdr->e_shentsize == sizeof(ELF_SECTION_HEADER_TYPE));
|
||||
ASSERT(elf_hdr->e_shoff + elf_hdr->e_shentsize * elf_hdr->e_shnum <= file_size);
|
||||
sec_hdr = (ELF_SECTION_HEADER_TYPE *)(file_map + elf_hdr->e_shoff);
|
||||
strtab = (char *)(file_map + sec_hdr[elf_hdr->e_shstrndx].sh_offset);
|
||||
for (i = 0; i < elf_hdr->e_shnum; i++) {
|
||||
if (strcmp(".text", strtab + sec_hdr->sh_name) == 0)
|
||||
return sec_hdr->sh_addr;
|
||||
++sec_hdr;
|
||||
}
|
||||
/* ELF doesn't require that there's a section named ".text". */
|
||||
ASSERT_CURIOSITY(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read until EOF or error. Return number of bytes read. */
|
||||
static size_t
|
||||
os_read_until(file_t fd, void *buf, size_t toread)
|
||||
{
|
||||
size_t orig_toread = toread;
|
||||
ssize_t nread;
|
||||
while (toread > 0) {
|
||||
nread = os_read(fd, buf, toread);
|
||||
if (nread <= 0)
|
||||
break;
|
||||
toread -= nread;
|
||||
buf = (app_pc)buf + nread;
|
||||
}
|
||||
return orig_toread - toread;
|
||||
}
|
||||
|
||||
bool
|
||||
elf_loader_init(elf_loader_t *elf, const char *filename)
|
||||
{
|
||||
memset(elf, 0, sizeof(*elf));
|
||||
elf->filename = filename;
|
||||
elf->fd = os_open(filename, OS_OPEN_READ);
|
||||
return elf->fd != INVALID_FILE;
|
||||
}
|
||||
|
||||
void
|
||||
elf_loader_destroy(elf_loader_t *elf)
|
||||
{
|
||||
if (elf->fd != INVALID_FILE) {
|
||||
os_close(elf->fd);
|
||||
}
|
||||
if (elf->file_map != NULL) {
|
||||
os_unmap_file(elf->file_map, elf->file_size);
|
||||
}
|
||||
memset(elf, 0, sizeof(*elf));
|
||||
}
|
||||
|
||||
ELF_HEADER_TYPE *
|
||||
elf_loader_read_ehdr(elf_loader_t *elf)
|
||||
{
|
||||
/* The initial read is sized to read both ehdr and all phdrs. */
|
||||
if (elf->fd == INVALID_FILE)
|
||||
return NULL;
|
||||
if (elf->file_map != NULL) {
|
||||
/* The user mapped the entire file up front, so use it. */
|
||||
elf->ehdr = (ELF_HEADER_TYPE *)elf->file_map;
|
||||
} else {
|
||||
size_t size = os_read_until(elf->fd, elf->buf, sizeof(elf->buf));
|
||||
if (size == 0)
|
||||
return NULL;
|
||||
if (!is_elf_so_header(elf->buf, size))
|
||||
return NULL;
|
||||
elf->ehdr = (ELF_HEADER_TYPE *)elf->buf;
|
||||
}
|
||||
return elf->ehdr;
|
||||
}
|
||||
|
||||
app_pc
|
||||
elf_loader_map_file(elf_loader_t *elf, bool reachable)
|
||||
{
|
||||
uint64 size64;
|
||||
if (elf->file_map != NULL)
|
||||
return elf->file_map;
|
||||
if (elf->fd == INVALID_FILE)
|
||||
return NULL;
|
||||
if (!os_get_file_size_by_handle(elf->fd, &size64))
|
||||
return NULL;
|
||||
ASSERT_TRUNCATE(elf->file_size, size_t, size64);
|
||||
elf->file_size = (size_t)size64; /* truncate */
|
||||
/* We use os_map_file instead of map_file since this mapping is temporary.
|
||||
* We don't need to add and remove it from dynamo_areas.
|
||||
*/
|
||||
elf->file_map =
|
||||
os_map_file(elf->fd, &elf->file_size, 0, NULL, MEMPROT_READ,
|
||||
MAP_FILE_COPY_ON_WRITE | (reachable ? MAP_FILE_REACHABLE : 0));
|
||||
return elf->file_map;
|
||||
}
|
||||
|
||||
ELF_PROGRAM_HEADER_TYPE *
|
||||
elf_loader_read_phdrs(elf_loader_t *elf)
|
||||
{
|
||||
size_t ph_off;
|
||||
size_t ph_size;
|
||||
if (elf->ehdr == NULL)
|
||||
return NULL;
|
||||
ph_off = elf->ehdr->e_phoff;
|
||||
ph_size = elf->ehdr->e_phnum * elf->ehdr->e_phentsize;
|
||||
if (elf->file_map == NULL && ph_off + ph_size < sizeof(elf->buf)) {
|
||||
/* We already read phdrs, and they are in buf. */
|
||||
elf->phdrs = (ELF_PROGRAM_HEADER_TYPE *)(elf->buf + elf->ehdr->e_phoff);
|
||||
} else {
|
||||
/* We have large or distant phdrs, so map the whole file. We could
|
||||
* seek and read just the phdrs to avoid disturbing the address space,
|
||||
* but that would introduce a dependency on DR's heap.
|
||||
*/
|
||||
if (elf_loader_map_file(elf, false /*!reachable*/) == NULL)
|
||||
return NULL;
|
||||
elf->phdrs = (ELF_PROGRAM_HEADER_TYPE *)(elf->file_map + elf->ehdr->e_phoff);
|
||||
}
|
||||
return elf->phdrs;
|
||||
}
|
||||
|
||||
bool
|
||||
elf_loader_read_headers(elf_loader_t *elf, const char *filename)
|
||||
{
|
||||
if (!elf_loader_init(elf, filename))
|
||||
return false;
|
||||
if (elf_loader_read_ehdr(elf) == NULL)
|
||||
return false;
|
||||
if (elf_loader_read_phdrs(elf) == NULL)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
app_pc
|
||||
elf_loader_map_phdrs(elf_loader_t *elf, bool fixed, map_fn_t map_func,
|
||||
unmap_fn_t unmap_func, prot_fn_t prot_func, modload_flags_t flags)
|
||||
{
|
||||
app_pc lib_base, lib_end, last_end;
|
||||
ELF_HEADER_TYPE *elf_hdr = elf->ehdr;
|
||||
app_pc map_base, map_end;
|
||||
reg_t pg_offs;
|
||||
uint seg_prot, i;
|
||||
ptr_int_t delta;
|
||||
size_t initial_map_size;
|
||||
|
||||
ASSERT(elf->phdrs != NULL && "call elf_loader_read_phdrs() first");
|
||||
if (elf->phdrs == NULL)
|
||||
return NULL;
|
||||
|
||||
map_base = module_vaddr_from_prog_header((app_pc)elf->phdrs, elf->ehdr->e_phnum, NULL,
|
||||
&map_end);
|
||||
|
||||
#ifndef NOT_DYNAMORIO_CORE_PROPER
|
||||
if (fixed &&
|
||||
(get_dynamorio_dll_start() < map_end && get_dynamorio_dll_end() > map_base)) {
|
||||
FATAL_USAGE_ERROR(FIXED_MAP_OVERLAPS_DR, 3, get_application_name(),
|
||||
get_application_pid(), elf->filename);
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
#endif
|
||||
|
||||
elf->image_size = map_end - map_base;
|
||||
|
||||
/* reserve the memory from os for library */
|
||||
initial_map_size = elf->image_size;
|
||||
#ifndef NOT_DYNAMORIO_CORE_PROPER
|
||||
if (INTERNAL_OPTION(separate_private_bss) && !TEST(MODLOAD_NOT_PRIVLIB, flags)) {
|
||||
/* place an extra no-access page after .bss */
|
||||
/* XXX: update privload_early_inject call to init_emulated_brk if this changes */
|
||||
/* XXX: should we avoid this for -early_inject's map of the app and ld.so? */
|
||||
initial_map_size += PAGE_SIZE;
|
||||
}
|
||||
#endif
|
||||
lib_base = (*map_func)(-1, &initial_map_size, 0, map_base,
|
||||
MEMPROT_NONE, /* so the separating page is no-access */
|
||||
MAP_FILE_COPY_ON_WRITE | MAP_FILE_IMAGE |
|
||||
/* i#1001: a PIE executable may have NULL as preferred
|
||||
* base, in which case the map can be anywhere
|
||||
*/
|
||||
((fixed && map_base != NULL) ? MAP_FILE_FIXED : 0) |
|
||||
(TEST(MODLOAD_REACHABLE, flags) ? MAP_FILE_REACHABLE : 0));
|
||||
ASSERT(lib_base != NULL);
|
||||
#ifndef NOT_DYNAMORIO_CORE_PROPER
|
||||
if (INTERNAL_OPTION(separate_private_bss) && initial_map_size > elf->image_size)
|
||||
elf->image_size = initial_map_size - PAGE_SIZE;
|
||||
else
|
||||
#endif
|
||||
elf->image_size = initial_map_size;
|
||||
lib_end = lib_base + elf->image_size;
|
||||
elf->load_base = lib_base;
|
||||
ASSERT(elf->load_delta == 0 || map_base == NULL);
|
||||
|
||||
if (map_base != NULL && map_base != lib_base) {
|
||||
/* the mapped memory is not at preferred address,
|
||||
* should be ok if it is still reachable for X64,
|
||||
* which will be checked later.
|
||||
*/
|
||||
LOG(GLOBAL, LOG_LOADER, 1, "%s: module not loaded at preferred address\n",
|
||||
__FUNCTION__);
|
||||
}
|
||||
delta = lib_base - map_base;
|
||||
elf->load_delta = delta;
|
||||
|
||||
/* walk over the program header to load the individual segments */
|
||||
last_end = lib_base;
|
||||
for (i = 0; i < elf_hdr->e_phnum; i++) {
|
||||
app_pc seg_base, seg_end, map, file_end;
|
||||
size_t seg_size;
|
||||
ELF_PROGRAM_HEADER_TYPE *prog_hdr =
|
||||
(ELF_PROGRAM_HEADER_TYPE *)((byte *)elf->phdrs + i * elf_hdr->e_phentsize);
|
||||
if (prog_hdr->p_type == PT_LOAD) {
|
||||
bool do_mmap = true;
|
||||
seg_base = (app_pc)ALIGN_BACKWARD(prog_hdr->p_vaddr, PAGE_SIZE) + delta;
|
||||
seg_end =
|
||||
(app_pc)ALIGN_FORWARD(prog_hdr->p_vaddr + prog_hdr->p_filesz, PAGE_SIZE) +
|
||||
delta;
|
||||
seg_size = seg_end - seg_base;
|
||||
if (seg_base != last_end) {
|
||||
/* XXX: a hole, I reserve this space instead of unmap it */
|
||||
size_t hole_size = seg_base - last_end;
|
||||
(*prot_func)(last_end, hole_size, MEMPROT_NONE);
|
||||
}
|
||||
seg_prot = module_segment_prot_to_osprot(prog_hdr);
|
||||
pg_offs = ALIGN_BACKWARD(prog_hdr->p_offset, PAGE_SIZE);
|
||||
if (TEST(MODLOAD_SKIP_WRITABLE, flags) && TEST(MEMPROT_WRITE, seg_prot) &&
|
||||
seg_end == lib_end) {
|
||||
/* We only actually skip if it's the final segment, to allow
|
||||
* unmapping with a single mmap and not worrying about sthg
|
||||
* else having been unmapped at the end in the meantime.
|
||||
*/
|
||||
do_mmap = false;
|
||||
elf->image_size = last_end - lib_base;
|
||||
}
|
||||
/* XXX:
|
||||
* This function can be called after dynamorio_heap_initialized,
|
||||
* and we will use map_file instead of os_map_file.
|
||||
* However, map_file does not allow mmap with overlapped memory,
|
||||
* so we have to unmap the old memory first.
|
||||
* This might be a problem, e.g.
|
||||
* one thread unmaps the memory and before mapping the actual file,
|
||||
* another thread requests memory via mmap takes the memory here,
|
||||
* a racy condition.
|
||||
*/
|
||||
if (seg_size > 0) { /* i#1872: handle empty segments */
|
||||
(*unmap_func)(seg_base, seg_size);
|
||||
if (do_mmap) {
|
||||
map = (*map_func)(
|
||||
elf->fd, &seg_size, pg_offs, seg_base /* base */,
|
||||
seg_prot | MEMPROT_WRITE /* prot */,
|
||||
MAP_FILE_COPY_ON_WRITE /*writes should not change file*/ |
|
||||
MAP_FILE_IMAGE |
|
||||
/* we don't need MAP_FILE_REACHABLE b/c we're fixed */
|
||||
MAP_FILE_FIXED);
|
||||
ASSERT(map != NULL);
|
||||
/* fill zeros at extend size */
|
||||
file_end = (app_pc)prog_hdr->p_vaddr + prog_hdr->p_filesz;
|
||||
if (seg_end > file_end + delta) {
|
||||
#ifndef NOT_DYNAMORIO_CORE_PROPER
|
||||
memset(file_end + delta, 0, seg_end - (file_end + delta));
|
||||
#else
|
||||
/* FIXME i#37: use a remote memset to zero out this gap or fix
|
||||
* it up in the child. There is typically one RW PT_LOAD
|
||||
* segment for .data and .bss. If .data ends and .bss starts
|
||||
* before filesz bytes, we need to zero the .bss bytes manually.
|
||||
*/
|
||||
#endif /* !NOT_DYNAMORIO_CORE_PROPER */
|
||||
}
|
||||
}
|
||||
}
|
||||
seg_end =
|
||||
(app_pc)ALIGN_FORWARD(prog_hdr->p_vaddr + prog_hdr->p_memsz, PAGE_SIZE) +
|
||||
delta;
|
||||
seg_size = seg_end - seg_base;
|
||||
if (seg_size > 0 && do_mmap)
|
||||
(*prot_func)(seg_base, seg_size, seg_prot);
|
||||
last_end = seg_end;
|
||||
}
|
||||
}
|
||||
ASSERT(last_end == lib_end);
|
||||
/* FIXME: recover from map failure rather than relying on asserts. */
|
||||
|
||||
return lib_base;
|
||||
}
|
||||
|
||||
/* Iterate program headers of a mapped ELF image and find the string that
|
||||
* PT_INTERP points to. Typically this comes early in the file and is always
|
||||
* included in PT_LOAD segments, so we safely do this after the initial
|
||||
* mapping.
|
||||
*/
|
||||
const char *
|
||||
elf_loader_find_pt_interp(elf_loader_t *elf)
|
||||
{
|
||||
int i;
|
||||
ELF_HEADER_TYPE *ehdr = elf->ehdr;
|
||||
ELF_PROGRAM_HEADER_TYPE *phdrs = elf->phdrs;
|
||||
|
||||
ASSERT(elf->load_base != NULL && "call elf_loader_map_phdrs() first");
|
||||
if (ehdr == NULL || phdrs == NULL || elf->load_base == NULL)
|
||||
return NULL;
|
||||
for (i = 0; i < ehdr->e_phnum; i++) {
|
||||
if (phdrs[i].p_type == PT_INTERP) {
|
||||
return (const char *)(phdrs[i].p_vaddr + elf->load_delta);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+11
-2
@@ -1,5 +1,5 @@
|
||||
/* **********************************************************
|
||||
* Copyright (c) 2011-2016 Google, Inc. All rights reserved.
|
||||
* Copyright (c) 2011-2019 Google, Inc. All rights reserved.
|
||||
* Copyright (c) 2008-2010 VMware, Inc. All rights reserved.
|
||||
* **********************************************************/
|
||||
|
||||
@@ -254,6 +254,12 @@ typedef struct elf_loader_t {
|
||||
byte buf[sizeof(ELF_HEADER_TYPE) + sizeof(ELF_PROGRAM_HEADER_TYPE) * 12];
|
||||
} elf_loader_t;
|
||||
|
||||
typedef byte *(*map_fn_t)(file_t f, size_t *size INOUT, uint64 offs, app_pc addr,
|
||||
uint prot /*MEMPROT_*/, map_flags_t map_flags);
|
||||
typedef bool (*unmap_fn_t)(byte *map, size_t size);
|
||||
typedef bool (*prot_fn_t)(byte *map, size_t size, uint prot /*MEMPROT_*/);
|
||||
typedef void (*check_bounds_fn_t)(elf_loader_t *elf, byte *start, byte *end);
|
||||
|
||||
/* Initialized an ELF loader for use with the given file. */
|
||||
bool
|
||||
elf_loader_init(elf_loader_t *elf, const char *filename);
|
||||
@@ -285,12 +291,15 @@ elf_loader_map_file(elf_loader_t *elf, bool reachable);
|
||||
* elf_loader_read_headers() shortcut. All image mappings are done via the
|
||||
* provided function pointers.
|
||||
*
|
||||
* check_bounds_func is only called if fixed=true.
|
||||
*
|
||||
* XXX: fixed is only a hint as PIEs with a base of 0 should not use MAP_FIXED,
|
||||
* should we remove it?
|
||||
*/
|
||||
app_pc
|
||||
elf_loader_map_phdrs(elf_loader_t *elf, bool fixed, map_fn_t map_func,
|
||||
unmap_fn_t unmap_func, prot_fn_t prot_func, modload_flags_t flags);
|
||||
unmap_fn_t unmap_func, prot_fn_t prot_func,
|
||||
check_bounds_fn_t check_bounds_func, modload_flags_t flags);
|
||||
|
||||
/* Iterate program headers of a mapped ELF image and find the string that
|
||||
* PT_INTERP points to. Typically this comes early in the file and is always
|
||||
|
||||
+4
-164
@@ -1,5 +1,5 @@
|
||||
/* *******************************************************************************
|
||||
* Copyright (c) 2013-2015 Google, Inc. All rights reserved.
|
||||
* Copyright (c) 2013-2019 Google, Inc. All rights reserved.
|
||||
* *******************************************************************************/
|
||||
|
||||
/*
|
||||
@@ -61,80 +61,6 @@
|
||||
#include <string.h> /* strcmp */
|
||||
#include <dlfcn.h>
|
||||
|
||||
#ifdef NOT_DYNAMORIO_CORE_PROPER
|
||||
# undef LOG
|
||||
# define LOG(...) /* nothing */
|
||||
# include <sys/utsname.h> /* for kernel_is_64bit */
|
||||
# undef ASSERT
|
||||
# define ASSERT(x) ((void)0)
|
||||
# undef ASSERT_NOT_IMPLEMENTED
|
||||
# define ASSERT_NOT_IMPLEMENTED(x) ((void)0)
|
||||
|
||||
/* Compatibility layer
|
||||
* XXX i#1409: really we should split out a lib shared w/ non-core from os.c.
|
||||
*/
|
||||
bool
|
||||
kernel_is_64bit(void)
|
||||
{
|
||||
struct utsname uinfo;
|
||||
if (uname(&uinfo) != 0)
|
||||
return true; /* guess */
|
||||
return (strncmp(uinfo.machine, "x86_64", sizeof("x86_64")) == 0);
|
||||
}
|
||||
|
||||
bool
|
||||
safe_read(const void *base, size_t size, void *out_buf)
|
||||
{
|
||||
memcpy(out_buf, base, size);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* XXX i#1345: support mixed-mode 32-bit and 64-bit in one process.
|
||||
* There is no official support for that on Linux or Windows and for now we do
|
||||
* not support it either, especially not mixing libraries.
|
||||
*/
|
||||
#ifdef X64
|
||||
typedef struct mach_header_64 mach_header_t;
|
||||
typedef struct segment_command_64 segment_command_t;
|
||||
typedef struct nlist_64 nlist_t;
|
||||
#else
|
||||
typedef struct mach_header mach_header_t;
|
||||
typedef struct segment_command segment_command_t;
|
||||
typedef struct nlist nlist_t;
|
||||
#endif
|
||||
|
||||
/* Like is_elf_so_header(), if size == 0 then safe-reads the header; else
|
||||
* assumes that [base, base+size) is readable.
|
||||
*/
|
||||
static bool
|
||||
is_macho_header(app_pc base, size_t size)
|
||||
{
|
||||
struct mach_header hdr_safe;
|
||||
struct mach_header *hdr;
|
||||
if (base == NULL)
|
||||
return false;
|
||||
if (size >= sizeof(hdr_safe)) {
|
||||
hdr = (struct mach_header *)base;
|
||||
} else {
|
||||
if (!safe_read(base, sizeof(hdr_safe), &hdr_safe))
|
||||
return false;
|
||||
hdr = &hdr_safe;
|
||||
}
|
||||
ASSERT(offsetof(struct mach_header, filetype) ==
|
||||
offsetof(struct mach_header_64, filetype));
|
||||
if ((hdr->magic == MH_MAGIC && hdr->cputype == CPU_TYPE_X86) ||
|
||||
(hdr->magic == MH_MAGIC_64 && hdr->cputype == CPU_TYPE_X86_64)) {
|
||||
/* We shouldn't see MH_PRELOAD as it can't be loaded by the kernel */
|
||||
if (hdr->filetype == MH_EXECUTE || hdr->filetype == MH_DYLIB ||
|
||||
hdr->filetype == MH_BUNDLE || hdr->filetype == MH_DYLINKER ||
|
||||
hdr->filetype == MH_FVMLIB) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
module_file_has_module_header(const char *filename)
|
||||
{
|
||||
@@ -157,7 +83,6 @@ module_is_partial_map(app_pc base, size_t size, uint memprot)
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef NOT_DYNAMORIO_CORE_PROPER
|
||||
bool
|
||||
module_walk_program_headers(app_pc base, size_t view_size, bool at_map, bool dyn_reloc,
|
||||
OUT app_pc *out_base /* relative pc */,
|
||||
@@ -318,7 +243,6 @@ module_num_program_headers(app_pc base)
|
||||
ASSERT_NOT_IMPLEMENTED(false); /* FIXME i#58: implement MachO support */
|
||||
return 0;
|
||||
}
|
||||
#endif /* !NOT_DYNAMORIO_CORE_PROPER */
|
||||
|
||||
bool
|
||||
module_read_program_header(app_pc base, uint segment_num,
|
||||
@@ -386,7 +310,6 @@ module_is_executable(app_pc base)
|
||||
return (hdr->filetype == MH_EXECUTE);
|
||||
}
|
||||
|
||||
#ifndef NOT_DYNAMORIO_CORE_PROPER
|
||||
/* ULEB128 is a little-endian 128-base encoding where msb is set if there's
|
||||
* another byte of data to add to the integer represented.
|
||||
*/
|
||||
@@ -547,7 +470,6 @@ get_proc_address(module_base_t lib, const char *name)
|
||||
{
|
||||
return get_proc_address_ex(lib, name, NULL);
|
||||
}
|
||||
#endif /* !NOT_DYNAMORIO_CORE_PROPER */
|
||||
|
||||
size_t
|
||||
module_get_header_size(app_pc module_base)
|
||||
@@ -556,84 +478,6 @@ module_get_header_size(app_pc module_base)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
platform_from_macho(file_t f, dr_platform_t *platform)
|
||||
{
|
||||
struct mach_header mach_hdr;
|
||||
if (os_read(f, &mach_hdr, sizeof(mach_hdr)) != sizeof(mach_hdr))
|
||||
return false;
|
||||
if (!is_macho_header((app_pc)&mach_hdr, sizeof(mach_hdr)))
|
||||
return false;
|
||||
switch (mach_hdr.cputype) {
|
||||
case CPU_TYPE_X86_64: *platform = DR_PLATFORM_64BIT; break;
|
||||
case CPU_TYPE_X86: *platform = DR_PLATFORM_32BIT; break;
|
||||
default: return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
module_get_platform(file_t f, dr_platform_t *platform, dr_platform_t *alt_platform)
|
||||
{
|
||||
struct fat_header fat_hdr;
|
||||
/* Both headers start with a 32-bit magic # */
|
||||
uint32_t magic;
|
||||
if (os_read(f, &magic, sizeof(magic)) != sizeof(magic) || !os_seek(f, 0, SEEK_SET))
|
||||
return false;
|
||||
if (magic == FAT_CIGAM) { /* big-endian */
|
||||
/* This is a "fat" or "universal" binary */
|
||||
struct fat_arch arch;
|
||||
uint num, i;
|
||||
bool found_main = false, found_alt = false;
|
||||
dr_platform_t local_alt = DR_PLATFORM_NONE;
|
||||
int64 cur_pos;
|
||||
if (os_read(f, &fat_hdr, sizeof(fat_hdr)) != sizeof(fat_hdr))
|
||||
return false;
|
||||
/* OSSwapInt32 is a macro, so there's no lib dependence here */
|
||||
num = OSSwapInt32(fat_hdr.nfat_arch);
|
||||
for (i = 0; i < num; i++) {
|
||||
if (os_read(f, &arch, sizeof(arch)) != sizeof(arch))
|
||||
return false;
|
||||
cur_pos = os_tell(f);
|
||||
/* The primary platform is the one that will be used on an execve,
|
||||
* which is the one that matches the kernel's bitwidth.
|
||||
*/
|
||||
if ((kernel_is_64bit() && OSSwapInt32(arch.cputype) == CPU_TYPE_X86_64) ||
|
||||
(!kernel_is_64bit() && OSSwapInt32(arch.cputype) == CPU_TYPE_X86)) {
|
||||
/* Line up right before the Mach-O header */
|
||||
if (!os_seek(f, OSSwapInt32(arch.offset), SEEK_SET))
|
||||
return false;
|
||||
if (!platform_from_macho(f, platform))
|
||||
return false;
|
||||
found_main = true;
|
||||
if (found_alt)
|
||||
break;
|
||||
} else if (OSSwapInt32(arch.cputype) == CPU_TYPE_X86_64 ||
|
||||
OSSwapInt32(arch.cputype) == CPU_TYPE_X86) {
|
||||
/* Line up right before the Mach-O header */
|
||||
if (!os_seek(f, OSSwapInt32(arch.offset), SEEK_SET))
|
||||
return false;
|
||||
if (platform_from_macho(f, &local_alt)) {
|
||||
found_alt = true;
|
||||
if (found_main)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!os_seek(f, cur_pos, SEEK_SET))
|
||||
return false;
|
||||
}
|
||||
if (!found_main && found_alt) {
|
||||
*platform = local_alt;
|
||||
local_alt = DR_PLATFORM_NONE;
|
||||
}
|
||||
if (alt_platform != NULL)
|
||||
*alt_platform = local_alt;
|
||||
return (found_main || found_alt);
|
||||
} else if (alt_platform != NULL)
|
||||
*alt_platform = DR_PLATFORM_NONE;
|
||||
return platform_from_macho(f, platform);
|
||||
}
|
||||
|
||||
bool
|
||||
module_has_text_relocs(app_pc base, bool at_map)
|
||||
{
|
||||
@@ -656,7 +500,6 @@ module_read_os_data(app_pc base, bool dyn_reloc, OUT ptr_int_t *load_delta,
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef NOT_DYNAMORIO_CORE_PROPER
|
||||
char *
|
||||
get_shared_lib_name(app_pc map)
|
||||
{
|
||||
@@ -683,13 +526,12 @@ module_get_os_privmod_data(app_pc base, size_t size, bool dyn_reloc,
|
||||
byte *
|
||||
module_dynamorio_lib_base(void)
|
||||
{
|
||||
# if defined(STATIC_LIBRARY) || defined(STANDALONE_UNIT_TEST)
|
||||
#if defined(STATIC_LIBRARY) || defined(STANDALONE_UNIT_TEST)
|
||||
return (byte *)&_mh_execute_header;
|
||||
# else
|
||||
#else
|
||||
return (byte *)&_mh_dylib_header;
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
#endif /* !NOT_DYNAMORIO_CORE_PROPER */
|
||||
|
||||
ptr_uint_t
|
||||
module_get_text_section(app_pc file_map, size_t file_size)
|
||||
@@ -698,7 +540,6 @@ module_get_text_section(app_pc file_map, size_t file_size)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef NOT_DYNAMORIO_CORE_PROPER
|
||||
bool
|
||||
module_dyld_shared_region(app_pc *start OUT, app_pc *end OUT)
|
||||
{
|
||||
@@ -803,4 +644,3 @@ module_walk_dyld_list(app_pc dyld_base)
|
||||
modinfo->imageFilePath, 0);
|
||||
}
|
||||
}
|
||||
#endif /* !NOT_DYNAMORIO_CORE_PROPER */
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* **********************************************************
|
||||
* Copyright (c) 2011-2018 Google, Inc. All rights reserved.
|
||||
* Copyright (c) 2011-2019 Google, Inc. All rights reserved.
|
||||
* Copyright (c) 2008-2010 VMware, Inc. All rights reserved.
|
||||
* **********************************************************/
|
||||
|
||||
@@ -96,6 +96,24 @@ struct _os_privmod_data_t {
|
||||
extern bool disallow_unsafe_static_calls;
|
||||
#endif
|
||||
|
||||
#ifdef MACOS
|
||||
/* XXX i#1345: support mixed-mode 32-bit and 64-bit in one process.
|
||||
* There is no official support for that on Linux or Windows and for now we do
|
||||
* not support it either, especially not mixing libraries.
|
||||
*/
|
||||
# ifdef X64
|
||||
typedef struct mach_header_64 mach_header_t;
|
||||
typedef struct segment_command_64 segment_command_t;
|
||||
typedef struct nlist_64 nlist_t;
|
||||
# else
|
||||
typedef struct mach_header mach_header_t;
|
||||
typedef struct segment_command segment_command_t;
|
||||
typedef struct nlist nlist_t;
|
||||
# endif
|
||||
bool
|
||||
is_macho_header(app_pc base, size_t size);
|
||||
#endif
|
||||
|
||||
void
|
||||
module_get_os_privmod_data(app_pc base, size_t size, bool relocated,
|
||||
OUT os_privmod_data_t *pd);
|
||||
|
||||
+830
-1393
File diff suppressed because it is too large
Load Diff
+19
-1
@@ -1,5 +1,5 @@
|
||||
/* **********************************************************
|
||||
* Copyright (c) 2011-2018 Google, Inc. All rights reserved.
|
||||
* Copyright (c) 2011-2019 Google, Inc. All rights reserved.
|
||||
* Copyright (c) 2008-2010 VMware, Inc. All rights reserved.
|
||||
* **********************************************************/
|
||||
|
||||
@@ -49,6 +49,17 @@
|
||||
#include "tls.h"
|
||||
#include "memquery.h"
|
||||
|
||||
/* Cross arch syscall nums for use with struct stat64. */
|
||||
#ifdef X64
|
||||
# ifdef SYS_stat
|
||||
# define SYSNUM_STAT SYS_stat
|
||||
# endif
|
||||
# define SYSNUM_FSTAT SYS_fstat
|
||||
#else
|
||||
# define SYSNUM_STAT SYS_stat64
|
||||
# define SYSNUM_FSTAT SYS_fstat64
|
||||
#endif
|
||||
|
||||
/* for inline asm */
|
||||
#ifdef X86
|
||||
# ifdef X64
|
||||
@@ -194,6 +205,13 @@ typedef struct ptrace_stack_args_t {
|
||||
char home_dir[MAXIMUM_PATH]; /* In case the user of the injectee is not us. */
|
||||
} ptrace_stack_args_t;
|
||||
|
||||
/* in drlibc_os.c */
|
||||
byte *
|
||||
mmap_syscall(byte *addr, size_t len, ulong prot, ulong flags, ulong fd, ulong offs);
|
||||
|
||||
long
|
||||
munmap_syscall(byte *addr, size_t len);
|
||||
|
||||
/* in os.c */
|
||||
bool
|
||||
os_thread_take_over(priv_mcontext_t *mc, kernel_sigset_t *sigset);
|
||||
|
||||
+12
-17
@@ -184,29 +184,24 @@ DR_export_target(drconfiglib)
|
||||
DR_install(TARGETS drconfiglib DESTINATION ${INSTALL_BIN})
|
||||
|
||||
# drconfiglib now uses drfront_access()
|
||||
target_link_libraries(drconfiglib drfrontendlib)
|
||||
# drconfiglib needs drlibc for dr_fpu_exception_init()
|
||||
target_link_libraries(drconfiglib drfrontendlib drlibc)
|
||||
if (UNIX AND X86)
|
||||
# We need our own memcpy + memset to avoid glibc versioning (i#1504).
|
||||
target_link_libraries(drconfiglib drmemfuncs)
|
||||
endif ()
|
||||
|
||||
if (WIN32)
|
||||
set(dr_frontend_srcs dr_frontend_win.c)
|
||||
else () #UNIX
|
||||
# We need os.c for os_open(), etc. for module_*.c.
|
||||
# XXX i#1409: create a nice isolated lib for this.
|
||||
set(dr_frontend_srcs dr_frontend_unix.c ../core/unix/os.c)
|
||||
if (APPLE)
|
||||
set(dr_frontend_srcs ${dr_frontend_srcs} ../core/unix/module_macho.c)
|
||||
else (APPLE)
|
||||
set(dr_frontend_srcs ${dr_frontend_srcs} ../core/unix/module_elf.c)
|
||||
endif (APPLE)
|
||||
else ()
|
||||
set(dr_frontend_srcs dr_frontend_unix.c)
|
||||
endif ()
|
||||
|
||||
|
||||
set(dr_frontend_srcs ${dr_frontend_srcs} dr_frontend_common.c)
|
||||
add_library(drfrontendlib STATIC ${dr_frontend_srcs})
|
||||
if (AARCH64)
|
||||
add_dependencies(drfrontendlib gen_aarch64_codec)
|
||||
endif()
|
||||
# We need drhelper for dynamorio_syscall for core/unix/os.c.
|
||||
target_link_libraries(drfrontendlib drhelper)
|
||||
if (UNIX)
|
||||
# We need drlibc for module-parsing routines.
|
||||
target_link_libraries(drfrontendlib drlibc)
|
||||
endif ()
|
||||
if (UNIX AND X86)
|
||||
# We need our own memcpy + memset to avoid glibc versioning (i#1504).
|
||||
target_link_libraries(drfrontendlib drmemfuncs)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#!/usr/bin/tclsh
|
||||
# **********************************************************
|
||||
# Copyright (c) 2019 Google, Inc. All rights reserved.
|
||||
# Copyright (c) 2017 ARM Limited. All rights reserved.
|
||||
# **********************************************************
|
||||
|
||||
@@ -71,8 +72,8 @@ set indent_exempt [list {aarch64/instr_create.h} {1} \
|
||||
{lib/hotpatch_interface.h} {1} \
|
||||
{lib/instrument.c} {1} \
|
||||
{lib/instrument_api.h} {1} \
|
||||
{lib/dr_helper.h} {1} \
|
||||
{lib/statsx.h} {1} \
|
||||
{drlibc/drlibc.h} {1} \
|
||||
{lib/statsx.h} {1} \
|
||||
{unix/os.c} {1} \
|
||||
{unix/signal.c} {1} \
|
||||
{unix/injector.c} {1} \
|
||||
|
||||
@@ -376,8 +376,10 @@ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${ARCH_LDFLAGS}")
|
||||
|
||||
# Must be AFTER build/include now that dr_api.h is configured.
|
||||
# We need this for Windows resources.rc to include globals_shared.h, and
|
||||
# for tools.c to include dr_helper.h.
|
||||
include_directories(AFTER ${PROJECT_SOURCE_DIR}/core/lib) # dr_helper.h
|
||||
# for tools.c to include drlibc.h.
|
||||
include_directories(AFTER
|
||||
${PROJECT_SOURCE_DIR}/core/drlibc # drlibc.h
|
||||
${PROJECT_SOURCE_DIR}/core/lib) # c_defines.h
|
||||
|
||||
# Since we're including configure.h we do not want any default defines.
|
||||
# Note that the new DynamoRIOConfig.cmake doesn't set these so we can
|
||||
@@ -428,7 +430,7 @@ if ("${CMAKE_GENERATOR}" MATCHES "Visual Studio")
|
||||
# for correct parallel builds we need a target
|
||||
add_dependencies(tools ${generate_tools_asm})
|
||||
endif ()
|
||||
target_link_libraries(tools drhelper)
|
||||
target_link_libraries(tools drlibc)
|
||||
|
||||
if (WIN32)
|
||||
set_source_files_properties(${PROJECT_SOURCE_DIR}/core/win32/resources.rc
|
||||
@@ -1698,7 +1700,9 @@ if (AARCH64)
|
||||
endif ()
|
||||
|
||||
if (CLIENT_INTERFACE AND NOT ANDROID) # XXX i#1874: get working on Android
|
||||
tobuild_api(libutil.frontend_test libutil/frontend_test.c "" "" OFF OFF)
|
||||
# We don't want to link with DR. We hack that for now by requesting drdecode so
|
||||
# we'll get the arch defs. XXX: Add a better way!
|
||||
tobuild_api(libutil.frontend_test libutil/frontend_test.c "" "" ON OFF)
|
||||
target_link_libraries(libutil.frontend_test drfrontendlib)
|
||||
endif ()
|
||||
|
||||
@@ -2323,7 +2327,7 @@ if (CLIENT_INTERFACE)
|
||||
use_DynamoRIO_extension(api.ibl-stress drcontainers)
|
||||
link_with_pthread(api.ibl-stress)
|
||||
if (WIN32)
|
||||
# On Windows, somehow linking with drcontainers inserts it and drhelper
|
||||
# On Windows, somehow linking with drcontainers inserts it and drlibc
|
||||
# in front of dynamorio.lib, despite being added to the link list later,
|
||||
# which results in unresolved symbols.
|
||||
# The only fix I could come up with is to force dynamorio.lib earlier
|
||||
@@ -3211,9 +3215,7 @@ if (UNIX)
|
||||
# The default value of CMAKE_SHARED_LIBRARY_LINK_C_FLAGS has -rdynamic,
|
||||
# which doesn't play well with clang and -static. Adding
|
||||
# --no-export-dynamic avoids the problem.
|
||||
# We get two copies of memcpy (from drhelper and from libc) so we avoid
|
||||
# linker warnings on gcc 6.x+ (i#1958).
|
||||
"-static -Wl,--no-export-dynamic -Wl,--allow-multiple-definition")
|
||||
"-static -Wl,--no-export-dynamic")
|
||||
endif ()
|
||||
# Test position independent executables.
|
||||
# FIXME i#1001: fib-pie fails with -early_inject.
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/* **********************************************************
|
||||
* Copyright (c) 2011-2018 Google, Inc. All rights reserved.
|
||||
* Copyright (c) 2011-2019 Google, Inc. All rights reserved.
|
||||
* Copyright (c) 2003-2010 VMware, Inc. All rights reserved.
|
||||
* **********************************************************/
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
|
||||
#define _GNU_SOURCE 1 /* for REG_RIP, etc. */
|
||||
#include "configure.h"
|
||||
#include "dr_helper.h"
|
||||
#include "drlibc.h"
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h> /* memcpy */
|
||||
|
||||
Reference in New Issue
Block a user