blob: c6a2fb6f2de0f59d8eac97e37e9a6ad2e69c16cc [file] [log] [blame]
/* **********************************************************
* Copyright (c) 2011-2014 Google, Inc. 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.
*/
#ifndef MODULE_LIST_H
#define MODULE_LIST_H
#include "heap.h" /* for HEAPACCT */
/* DR_API EXPORT TOFILE dr_tools.h */
/* DR_API EXPORT BEGIN */
/**************************************************
* MODULE INFORMATION TYPES
*/
/**
* Type used for dr_get_proc_address(). This can be obtained from the
* #_module_data_t structure. It is equivalent to the base address of
* the module on both Windows and Linux.
*/
#ifdef AVOID_API_EXPORT
/* Rather than using a void * for the module base, we forward declare a struct
* that we never define. This prevents usage errors such as passing a
* module_data_t* to dr_get_proc_address().
*/
#endif
struct _module_handle_t;
typedef struct _module_handle_t * module_handle_t;
#ifdef WINDOWS
#define MODULE_FILE_VERSION_INVALID ULLONG_MAX
/**
* Used to hold .rsrc section version number information. This number is usually
* presented as p1.p2.p3.p4 by PE parsing tools.
*/
typedef union _version_number_t {
uint64 version; /**< Representation as a 64-bit integer. */
struct {
uint ms; /**< */
uint ls; /**< */
} version_uint; /**< Representation as 2 32-bit integers. */
struct {
ushort p2; /**< */
ushort p1; /**< */
ushort p4; /**< */
ushort p3; /**< */
} version_parts; /**< Representation as 4 16-bit integers. */
} version_number_t;
#endif
/* DR_API EXPORT END */
#include "module.h" /* include os_specific header */
/* DR_API EXPORT TOFILE dr_tools.h */
/* DR_API EXPORT BEGIN */
/**
* Holds the names of a module. This structure contains multiple
* fields corresponding to different sources of a module name. Note
* that some of these names may not exist for certain modules. It is
* highly likely, however, that at least one name is available. Use
* dr_module_preferred_name() on the parent _module_data_t to get the
* preferred name of the module.
*/
typedef struct _module_names_t {
const char *module_name; /**< On windows this name comes from the PE header exports
* section (NULL if the module has no exports section). On
* Linux the name will come from the ELF DYNAMIC program
* header (NULL if the module has no SONAME entry). */
const char *file_name; /**< The file name used to load this module. Note - on Windows
* this is not always available. */
#ifdef WINDOWS
const char *exe_name; /**< If this module is the main executable of this process then
* this is the executable name used to launch the process (NULL
* for all other modules). */
const char *rsrc_name; /**< The internal name given to the module in its resource
* section. Will be NULL if the module has no resource section
* or doesn't set this field within it. */
#else /* UNIX */
uint64 inode; /**< The inode of the module file mapped in. */
#endif
} module_names_t;
/* DR_API EXPORT END */
#ifdef WINDOWS
/* Introduced as part of case 9842; see module_names_t above. Shouldn't
* put case number in exported parts (CLIENT api), so adding it here.
*
* The name precedence order is as follows,
* Choice #1: PE exports name.
* Choice #2: executable qualified name (This would be the last choice
* except historically it's been #2 so we'll stick with that).
* Choice #3: .rsrc original filename, already strduped.
* Choice #4: file name.
*/
#define GET_MODULE_NAME(mod_names) \
(((mod_names)->module_name != NULL) ? (mod_names)->module_name : \
(((mod_names)->exe_name != NULL) ? (mod_names)->exe_name : \
(((mod_names)->rsrc_name != NULL) ? (mod_names)->rsrc_name : \
(((mod_names)->file_name != NULL) ? (mod_names)->file_name : NULL))))
#else
/* For Linux the precedence order is as follows,
* Choice #1: the module_name (SONAME entry from the DYNAMIC program_header, if it exists)
* Choice #2: the filename of the file mapped in (from the maps file)
*/
#define GET_MODULE_NAME(mod_names) \
(((mod_names)->module_name != NULL) ? (mod_names)->module_name : \
(((mod_names)->file_name != NULL) ? (mod_names)->file_name : NULL))
#endif
/* Used to augments the basic vm_area_vector_t interval, all fields that
* we get from the loader or PE/ELF header should be maintained here. This is what
* we store in the loaded_modules_areas vector. */
typedef struct _module_area_t {
/* vm_area_t has start and end fields, but we're duplicating them in module_data_t so
* the information is available to the module iterator. */
/* On windows start-end bound the view of the module that was mapped. This view size
* is almost always the same as the internal_size == pe size (the full size of the
* module). On Vista we've seen drivers mapped into user processes (leading to
* view size = PAGE_ALIGN(pe_size) > pe size) and partial mappings of child
* executables (leading to view size < pe_size). */
/* To support non-contiguous library mappings on Linux (i#160/PR 562667)
* we have the os-specific routines add each module segment to the
* vmvector. We store no data here on that but rely on the vector and
* on checking whether the vector entry's start == this start to know
* which entry is the primary entry for a module.
* We still store the maximum endpoint in the end field (after this
* data structure is fully initialized). Use module_contains_addr() to
* check for overlap, rather than checking [start..end).
*/
app_pc start;
app_pc end;
app_pc entry_point;
uint flags;
module_names_t names;
char *full_path;
os_module_data_t os_data; /* os specific data for this module */
} module_area_t;
/* Flags used in module_area_t.flags */
enum {
/* case 9653: only the 1st coarse unit in a module's +x region(s) is persisted */
MODULE_HAS_PRIMARY_COARSE = 0x00000001,
#if defined(RETURN_AFTER_CALL) || defined(RCT_IND_BRANCH)
/* case 8648: did we load persisted RCT data for the whole module? */
MODULE_RCT_LOADED = 0x00000002,
#endif
#ifdef RETURN_AFTER_CALL /* should include RCT_IND_BRANCH but matching other code */
MODULE_HAS_BORLAND_SEH = 0x00000004,
#endif
/* case 9672: used to detect whether to preserve persisted RCT on a flush */
MODULE_BEING_UNLOADED = 0x00000008,
/* case 9799: used to ensure persistent caches are safe to use */
MODULE_WAS_EXEMPTED = 0x00000010,
#if defined(X64) && (defined(RETURN_AFTER_CALL) || defined(RCT_IND_BRANCH))
/* PR 277064/277044: have we scanned the module yet? */
MODULE_RCT_SCANNED = 0x00000020,
#endif
#ifdef WINDOWS
/* do not created a persistent cache from this module */
MODULE_DO_NOT_PERSIST = 0x00000040,
#endif
#ifdef CLIENT_INTERFACE
MODULE_NULL_INSTRUMENT = 0x00000080,
#endif
};
/**************** init/exit routines *****************/
void modules_init(void);
bool is_module_list_initialized(void);
void modules_exit(void);
void modules_reset_list(void);
/**************** module_list updating routines *****************/
void module_list_add(app_pc base, size_t view_size, bool at_map, const char *filepath
_IF_UNIX(uint64 inode));
void module_list_remove(app_pc base, size_t view_size);
void module_list_add_mapping(module_area_t *ma, app_pc map_start, app_pc map_end);
void module_list_remove_mapping(module_area_t *ma, app_pc map_start, app_pc map_end);
/**************** module_data_lock routines *****************/
void os_get_module_info_lock(void);
void os_get_module_info_unlock(void);
void os_get_module_info_write_lock(void);
void os_get_module_info_write_unlock(void);
bool os_get_module_info_locked(void);
bool os_get_module_info_write_locked(void);
/**************** module flag routines *****************/
bool os_module_set_flag(app_pc module_base, uint flag);
bool os_module_clear_flag(app_pc module_base, uint flag);
bool os_module_get_flag(app_pc module_base, uint flag);
/**************** module_area accessor routines (os shared) *****************/
module_area_t * module_pc_lookup(byte *pc);
bool module_overlaps(byte *pc, size_t len);
/* Unlike os_get_module_info(), sets *name to NULL if return value is false */
bool os_get_module_name(const app_pc pc, /*OUT*/ const char **name);
const char * os_get_module_name_strdup(const app_pc pc HEAPACCT(which_heap_t which));
/* Returns the number of characters copied (maximum is buf_len -1).
* If there is no module at pc, or no module name available, 0 is
* returned and the buffer set to "".
*/
size_t os_get_module_name_buf(const app_pc pc, char *buf, size_t buf_len);
/* Copies the module name into buf and returns a pointer to buf,
* unless buf is too small, in which case the module name is strdup-ed
* and a pointer to it returned (which the caller must strfree).
* If there is no module name, returns NULL.
*/
const char * os_get_module_name_buf_strdup(const app_pc pc, char *buf, size_t buf_len
HEAPACCT(which_heap_t which));
size_t os_module_get_view_size(app_pc module_base);
bool module_contains_addr(module_area_t *ma, app_pc pc);
/**************** module iterator routines *****************/
/* module iterator fields */
typedef struct _module_iterator_t module_iterator_t;
/* If plan to write to module_area fields must call os_get_module_info_write_[un]lock
* around entire usage of the iterator. */
module_iterator_t * module_iterator_start(void);
bool module_iterator_hasnext(module_iterator_t *mi);
module_area_t * module_iterator_next(module_iterator_t *mi);
void module_iterator_stop(module_iterator_t *mi);
/***************** in os specific module.c *****************/
void os_modules_init(void);
void os_modules_exit(void);
void os_module_area_init(module_area_t *ma, app_pc base, size_t view_size,
bool at_map, const char *filepath
_IF_UNIX(uint64 inode) HEAPACCT(which_heap_t which));
void os_module_area_reset(module_area_t *ma HEAPACCT(which_heap_t which));
void free_module_names(module_names_t *mod_names HEAPACCT(which_heap_t which));
#ifdef UNIX
/* returns true if the module is marked as having text relocations */
bool module_has_text_relocs(app_pc base, bool at_map);
#endif
/**************************************************************************************/
/* Moved from os_shared.h to use typedefs here, in <os>/module.c
* Should clean up and see if these can be shared/obsoleted by the os shared mod list. */
bool os_get_module_info_all_names(const app_pc pc,
/* FIXME PR 215890: does ELF64 use 64-bit timestamp
* or checksum?
*/
uint *checksum, uint *timestamp,
size_t *size, module_names_t **names,
size_t *code_size, uint64 *file_version);
/* We'd like to have these get_proc_address* routines take a module_handle_t for
* type safety, but we have too much DR internal code that passes HMODULE,
* HANDLE, and app_pc values to these routines. Instead we use this
* module_base_t typedef internally, so we can freely convert from handles to
* void*'s and app_pcs.
*/
typedef void *module_base_t;
generic_func_t
get_proc_address(module_base_t lib, const char *name);
#ifdef UNIX
/* if we add any more values, switch to a globally-defined dr_export_info_t
* and use it here
*/
generic_func_t
get_proc_address_ex(module_base_t lib, const char *name, bool *is_indirect_code OUT);
#else /* WINDOWS */
generic_func_t
get_proc_address_ex(module_base_t lib, const char *name, const char **forwarder OUT);
generic_func_t
get_proc_address_by_ordinal(module_base_t lib, uint ordinal, const char **forwarder OUT);
# ifdef CLIENT_INTERFACE
generic_func_t
get_proc_address_resolve_forward(module_base_t lib, const char *name);
# endif
#endif /* WINDOWS */
#ifdef WINDOWS
void *
get_remote_process_entry(HANDLE process_handle, OUT bool *x86_code);
#endif
void print_modules(file_t f, bool dump_xml);
const char *get_module_short_name(app_pc pc HEAPACCT(which_heap_t which));
app_pc get_module_base(app_pc pc);
/* Returns true if [start_pc, end_pc) is within a single code section.
* Returns the bounds of the enclosing section in sec_start and sec_end.
* Note that unlike is_in_*_section routines, does NOT merge adjacent sections. */
bool is_range_in_code_section(app_pc module_base, app_pc start_pc, app_pc end_pc,
app_pc *sec_start /* OPTIONAL OUT */,
app_pc *sec_end /* OPTIONAL OUT */);
/* Returns true if addr is in a code section and if so returns in sec_start and sec_end
* the bounds of the section containing addr (MERGED with adjacent code sections). */
bool is_in_code_section(app_pc module_base, app_pc addr,
app_pc *sec_start /* OPTIONAL OUT */,
app_pc *sec_end /* OPTIONAL OUT */);
/* Same as above only for initialized data sections instead of code. */
bool is_in_dot_data_section(app_pc module_base, app_pc addr,
app_pc *sec_start /* OPTIONAL OUT */,
app_pc *sec_end /* OPTIONAL OUT */);
/* Same as above only for any section instead of code. */
bool is_in_any_section(app_pc module_base, app_pc addr,
app_pc *sec_start /* OPTIONAL OUT */,
app_pc *sec_end /* OPTIONAL OUT */);
bool is_mapped_as_image(app_pc module_base);
bool os_get_module_info(const app_pc pc, uint *checksum,
uint *timestamp, size_t *size, const char **name,
size_t *code_size, uint64 *file_version);
static inline bool
module_info_exists(const app_pc pc)
{
return os_get_module_info(pc, NULL, NULL, NULL, NULL, NULL, NULL);
}
bool get_named_section_bounds(app_pc module_base, const char *name,
app_pc *start/*OUT*/, app_pc *end/*OUT*/);
bool get_module_company_name(app_pc mod_base, char *out_buf, size_t out_buf_size);
#if defined(RETURN_AFTER_CALL) || defined(RCT_IND_BRANCH)
rct_module_table_t *
os_module_get_rct_htable(app_pc pc, rct_type_t which);
#endif
bool
module_get_nth_segment(app_pc module_base, uint n,
app_pc *start/*OPTIONAL OUT*/, app_pc *end/*OPTIONAL OUT*/,
uint *chars/*OPTIONAL OUT*/);
size_t
module_get_header_size(app_pc module_base);
typedef struct {
/* MD5 of portions of files mapped as image sections */
byte full_MD5[MD5_RAW_BYTES];
/* a full digest uses all readable raw bytes (as also present in
* the file) in sections loaded in memory */
/* Note that for most files this should result in the same value
* as md5sum, except for files with digital signatures or
* debugging information that is not loaded in memory */
/* an MD5 digest of only header and footer of file with lengths
* specified by aslr_short_digest */
byte short_MD5[MD5_RAW_BYTES];
/* FIXME: case 4678 about possible NYI subregion checksums
* amenable to lazy evaluation. Such digests which will be of
* dynamic size and file offset which will have to be specified
* here. */
} module_digest_t;
/* FIXME: rename since being used for module-independent purposes? */
void
module_calculate_digest(/*OUT*/ module_digest_t *digest,
app_pc module_base,
size_t module_size,
bool full_digest,
bool short_digest,
uint short_digest_size,
uint sec_char_include,
uint sec_char_exclude);
/* actually in utils.c since os-independent */
bool
module_digests_equal(const module_digest_t *calculated_digest,
const module_digest_t *matching_digest,
bool check_short, bool check_full);
/***************************************************************************/
/* DR's custom loader related data structure and functions,
* which should be used by loader only.
*/
/* List of privately-loaded modules.
* We assume there will only be a handful of privately-loaded modules,
* so we do not bother to optimize: we use a linked list, search by
* linear walk, and find exports by walking the PE structures each time.
* The list is kept in reverse-dependent order so we can unload from the
* front without breaking dependencies.
*/
typedef struct _privmod_t {
app_pc base;
size_t size;
const char *name;
char path[MAXIMUM_PATH];
uint ref_count;
bool externally_loaded;
#ifdef CLIENT_INTERFACE
bool is_client; /* or Extension */
#endif
struct _privmod_t *next;
struct _privmod_t *prev;
void *os_privmod_data;
} privmod_t;
/* more os independent name */
#ifdef WINDOWS
# define DLL_PROCESS_INIT DLL_PROCESS_ATTACH
# define DLL_PROCESS_EXIT DLL_PROCESS_DETACH
# define DLL_THREAD_INIT DLL_THREAD_ATTACH
# define DLL_THREAD_EXIT DLL_THREAD_DETACH
#else
# define DLL_PROCESS_INIT 1
# define DLL_PROCESS_EXIT 2
# define DLL_THREAD_INIT 3
# define DLL_THREAD_EXIT 4
#endif
/* We need to load client libs prior to having heap */
#define PRIVMOD_STATIC_NUM 8
/* It should have more entries than the PRIVMOD_STATIC_NUM,
* as it may also contains the extension libraries and
* externally loaded libraries, as well as our rpath-file search paths.
*/
#define SEARCH_PATHS_NUM (3*PRIVMOD_STATIC_NUM)
extern recursive_lock_t privload_lock;
extern char search_paths[SEARCH_PATHS_NUM][MAXIMUM_PATH];
extern uint search_paths_idx;
extern vm_area_vector_t *modlist_areas;
/***************************************************************************
* Public functions
*/
/* returns whether they all fit */
bool
privload_print_modules(bool path, bool lock, char *buf, size_t bufsz, size_t *sofar);
/* ************************************************************************* *
* os independent functions in loader_shared.c, can be called from loader.c *
* ************************************************************************* */
privmod_t *
privload_load(const char *filename, privmod_t *dependent, bool reachable);
bool
privload_unload(privmod_t *privmod);
privmod_t *
privload_lookup(const char *name);
privmod_t *
privload_lookup_by_base(app_pc modbase);
privmod_t *
privload_lookup_by_pc(app_pc modbase);
/* name is assumed to be in immutable persistent storage.
* a copy of path is made.
*/
privmod_t *
privload_insert(privmod_t *after, app_pc base, size_t size, const char *name,
const char *path);
/* ************************************************************************* *
* os specific functions in loader.c, can be called from loader_shared.c *
* ************************************************************************* */
/* searches in standard paths instead of requiring abs path */
app_pc
privload_load_private_library(const char *name, bool reachable);
void
privload_redirect_setup(privmod_t *mod);
void
privload_os_finalize(privmod_t *privmod_t);
app_pc
privload_map_and_relocate(const char *filename, size_t *size OUT, bool reachable);
bool
privload_call_entry(privmod_t *privmod, uint reason);
bool
privload_process_imports(privmod_t *mod);
bool
privload_unload_imports(privmod_t *mod);
void
privload_unmap_file(privmod_t *mod);
void
privload_add_areas(privmod_t *privmod);
void
privload_remove_areas(privmod_t *privmod);
void
privload_add_drext_path(void);
privmod_t *
privload_next_module(privmod_t *mod);
privmod_t *
privload_first_module(void);
/* os specific loader initialization prologue before finalize the load,
* will also acquire privload_lock.
*/
void
os_loader_init_prologue(void);
/* os specific loader initialization epilogue after finalize the load,
* will release privload_lock.
*/
void
os_loader_init_epilogue(void);
void
os_loader_exit(void);
/* os specific thread initilization prologue for loader, holding no lock */
void
os_loader_thread_init_prologue(dcontext_t *dcontext);
/* os specific thread initilization epilogue for loader, holding no lock */
void
os_loader_thread_init_epilogue(dcontext_t *dcontext);
/* os specific thread exit for loader, holding no lock */
void
os_loader_thread_exit(dcontext_t *dcontext);
char *
get_shared_lib_name(app_pc map);
app_pc
get_image_entry(void);
void
privload_load_finalized(privmod_t *mod);
#ifdef WINDOWS
bool
privload_console_share(app_pc priv_kernel32, app_pc app_kernel32);
#endif
#endif /* MODULE_LIST_H */