* Copyright (c) 2011-2021 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_SHARED_H
#define MODULE_SHARED_H
#include "heap.h"
#include "module_api.h"
#include "module.h"
#ifdef WINDOWS
* 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
* 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
* we get from the loader or PE/ELF header should be maintained here. This is what
* we store in the loaded_module_areas vector. */
typedef struct _module_area_t {
* the information is available to the module iterator. */
* 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). */
* 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;
} module_area_t;
enum {
MODULE_HAS_PRIMARY_COARSE = 0x00000001,
#if defined(RETURN_AFTER_CALL) || defined(RCT_IND_BRANCH)
MODULE_RCT_LOADED = 0x00000002,
#endif
#ifdef RETURN_AFTER_CALL
MODULE_HAS_BORLAND_SEH = 0x00000004,
#endif
MODULE_BEING_UNLOADED = 0x00000008,
MODULE_WAS_EXEMPTED = 0x00000010,
#if defined(X64) && (defined(RETURN_AFTER_CALL) || defined(RCT_IND_BRANCH))
MODULE_RCT_SCANNED = 0x00000020,
#endif
#ifdef WINDOWS
MODULE_DO_NOT_PERSIST = 0x00000040,
#endif
MODULE_NULL_INSTRUMENT = 0x00000080,
MODULE_LOAD_EVENT = 0x00000100,
};
void
modules_init(void);
bool
is_module_list_initialized(void);
void
modules_exit(void);
void
modules_reset_list(void);
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);
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);
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);
bool
pc_is_in_module(byte *pc);
module_area_t *
module_pc_lookup(byte *pc);
bool
module_overlaps(byte *pc, size_t len);
bool
os_get_module_name(const app_pc pc, const char **name);
const char *
os_get_module_name_strdup(const app_pc pc HEAPACCT(which_heap_t which));
* 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);
* 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);
typedef struct _module_iterator_t module_iterator_t;
* 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);
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
bool
module_has_text_relocs(app_pc base, bool at_map);
#endif
void
module_copy_os_data(os_module_data_t *dst, os_module_data_t *src);
* 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,
* or checksum?
*/
uint *checksum, uint *timestamp, size_t *size,
module_names_t **names, size_t *code_size,
uint64 *file_version);
* 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
d_r_get_proc_address(module_base_t lib, const char *name);
#ifdef UNIX
* and use it here
*/
generic_func_t
get_proc_address_ex(module_base_t lib, const char *name, bool *is_indirect_code OUT);
#else
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);
generic_func_t
get_proc_address_resolve_forward(module_base_t lib, const char *name);
#endif
#ifdef WINDOWS
uint64
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 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 ,
app_pc *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 ,
app_pc *sec_end );
bool
is_in_dot_data_section(app_pc module_base, app_pc addr,
app_pc *sec_start ,
app_pc *sec_end );
bool
is_in_any_section(app_pc module_base, app_pc addr, app_pc *sec_start ,
app_pc *sec_end );
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 ,
app_pc *end );
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 ,
app_pc *end , uint *chars );
size_t
module_get_header_size(app_pc module_base);
typedef struct {
byte full_MD5[MD5_RAW_BYTES];
* the file) in sections loaded in memory */
* as md5sum, except for files with digital signatures or
* debugging information that is not loaded in memory */
* specified by aslr_short_digest */
byte short_MD5[MD5_RAW_BYTES];
* 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;
void
module_calculate_digest( module_digest_t *digest, app_pc module_base,
size_t module_size, bool full_digest, bool short_digest,
size_t short_digest_size, uint sec_char_include,
uint sec_char_exclude);
bool
module_digests_equal(const module_digest_t *calculated_digest,
const module_digest_t *matching_digest, bool check_short,
bool check_full);
* which should be used by loader only.
*/
* 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;
bool is_client;
bool called_proc_entry;
bool called_proc_exit;
struct _privmod_t *next;
struct _privmod_t *prev;
void *os_privmod_data;
} privmod_t;
#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
#define PRIVMOD_STATIC_NUM 8
* 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
*/
typedef enum {
MODLOAD_REACHABLE = 0x0001,
MODLOAD_NOT_PRIVLIB = 0x0002,
MODLOAD_SKIP_WRITABLE = 0x0004,
* Places an extra no-access page after .bss.
*/
MODLOAD_SEPARATE_BSS = 0x0008,
MODLOAD_SEPARATE_PROCESS = 0x0010,
* distortions for app mappings (e.g., early inject mapping the interpreter).
*/
MODLOAD_IS_APP = 0x0020,
} modload_flags_t;
app_pc
privload_map_and_relocate(const char *filename, size_t *size OUT, modload_flags_t flags);
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);
* 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);
bool
privload_search_path_exists(const char *path, size_t len);
* os specific functions in loader.c, can be called from loader_shared.c *
* ************************************************************************* */
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);
bool
privload_call_entry(dcontext_t *dcontext, 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);
bool
privload_fill_os_module_info(app_pc base, OUT app_pc *out_base ,
OUT app_pc *out_max_end ,
OUT char **out_soname, OUT os_module_data_t *out_data);
* will also acquire privload_lock.
*/
void
os_loader_init_prologue(void);
* will release privload_lock.
*/
void
os_loader_init_epilogue();
void
os_loader_exit(void);
void
os_loader_thread_init_prologue(dcontext_t *dcontext);
void
os_loader_thread_init_epilogue(dcontext_t *dcontext);
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);
bool
privload_attach_parent_console(app_pc app_kernel32);
#endif
* they are also used by __wrap_* functions in instrument.c
*/
#ifdef DEBUG
# define DR_DISALLOW_UNSAFE_STATIC_NAME "_DR_DISALLOW_UNSAFE_STATIC_"
extern bool disallow_unsafe_static_calls;
#endif
* The returned address is guaranteed to be double-pointer-aligned:
* aligned to 16 bytes for 64-bit; aligned to 8 bytes for 32-bit.
*/
#define STANDARD_HEAP_ALIGNMENT IF_X64_ELSE(16, 8)
void *
redirect_calloc(size_t nmemb, size_t size);
void *
redirect_malloc(size_t size);
void
redirect_free(void *mem);
void *
redirect_realloc(void *mem, size_t size);
char *
redirect_strdup(const char *str);
size_t
redirect_malloc_requested_size(void *mem);
#ifdef DEBUG
void *
redirect_malloc_initonly(size_t size);
void *
redirect_realloc_initonly(void *mem, size_t size);
void *
redirect_calloc_initonly(size_t nmemb, size_t size);
void
redirect_free_initonly(void *mem);
char *
redirect_strdup_initonly(const char *str);
#endif
#endif