mirror of
https://github.com/DynamoRIO/dynamorio.git
synced 2026-10-12 02:02:04 +00:00
- Update `core/kernel_linux/CMakeLists.txt`: - Include source files in `core/` as dependencies for kernel module. - Define `LINUX_KERNEL`, `DYNAMORIO_INTERNAL`, `DR_DO_NOT_DEFINE_MAX_MIN` - Add `-Wframe-larger-than=4096` - Update include headers in source files under `core/`. This includes using wrapper headers (e.g., `stdarg_wrapper.h`) or excluding headers that don't have an equivalent in kernel (e.g., `math.h`). - Exclude floating point arithmetic and user space specific logic (e.g., signal handling, rseq) from kernel build. - Optimize frame stack in `options.c` to make frame less than 4KB. Issue: #8021
618 lines
22 KiB
C
618 lines
22 KiB
C
/* **********************************************************
|
|
* Copyright (c) 2012-2026 Google, Inc. All rights reserved.
|
|
* Copyright (c) 2000-2008 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 */
|
|
|
|
/*
|
|
* link.h - link exports
|
|
*/
|
|
|
|
#ifndef _CORE_LINK_H_ /* using different define than /usr/include/link.h */
|
|
#define _CORE_LINK_H_
|
|
|
|
/* linkstub_t flags
|
|
* WARNING: flags field is a ushort, so max flag is 0x8000!
|
|
*/
|
|
enum {
|
|
/***************************************************/
|
|
/* these first flags are also used on the instr_t data structure */
|
|
|
|
/* Type of branch and thus which struct is used for this exit.
|
|
* Due to a tight namespace (flags is a ushort field), we pack our
|
|
* 3 types into these 2 bits, so the LINKSTUB_ macros are used to
|
|
* distinguish, rather than raw bit tests:
|
|
*
|
|
* name LINK_DIRECT LINK_INDIRECT struct
|
|
* --------------- --- --- --------------------------
|
|
* (subset of fake) 0 0 linkstub_t
|
|
* normal direct 1 0 direct_linkstub_t
|
|
* normal indirect 0 1 indirect_linkstub_t
|
|
* cbr fallthrough 1 1 cbr_fallthrough_linkstub_t
|
|
*
|
|
* Note that we can have fake linkstubs that should be treated as
|
|
* direct or indirect, so LINK_FAKE is a separate flag.
|
|
*/
|
|
LINK_DIRECT = 0x0001,
|
|
LINK_INDIRECT = 0x0002,
|
|
/* more specifics on type of branch
|
|
* must check LINK_DIRECT vs LINK_INDIRECT for JMP and CALL.
|
|
* absence of all of these is relied on as an indicator of shared_syscall
|
|
* in indirect_linkstub_target(), so we can't get rid of LINK_RETURN
|
|
* and use absence of CALL & JMP to indicate it.
|
|
*/
|
|
LINK_RETURN = 0x0004,
|
|
/* JMP|CALL indicates JMP_PLT, so use EXIT_IS_{JMP,CALL} rather than these raw bits */
|
|
LINK_CALL = 0x0008,
|
|
LINK_JMP = 0x0010,
|
|
|
|
/* Indicates a far cti which uses a separate ibl entry */
|
|
LINK_FAR = 0x0020,
|
|
|
|
/* This exit cti has a preceding NOP to avoid its immediate from crossing a cache
|
|
* line. This flag lets us identify NOPs which we added as opposed to the client.
|
|
*/
|
|
LINK_PADDED = 0x0040,
|
|
|
|
#ifdef X64
|
|
/* PR 257963: since we don't store targets of ind branches, we need a flag
|
|
* so we know whether this is a trace cmp exit, which has its own ibl entry
|
|
*/
|
|
LINK_TRACE_CMP = 0x0080,
|
|
#endif
|
|
/* Flags that tell DR to take some action upon returning to d_r_dispatch.
|
|
* This first one is multiplexed via dcontext->upcontext.upcontext.exit_reason.
|
|
* All uses are assumed to be unlinkable.
|
|
*/
|
|
LINK_SPECIAL_EXIT = 0x0100,
|
|
#ifdef WINDOWS
|
|
LINK_CALLBACK_RETURN = 0x0200,
|
|
#else
|
|
/* PR 286922: we support both OP_sys{call,enter}- and OP_int-based system calls */
|
|
LINK_NI_SYSCALL_INT = 0x0200,
|
|
#endif
|
|
/* indicates whether exit is before a non-ignorable syscall */
|
|
LINK_NI_SYSCALL = 0x0400,
|
|
LINK_FINAL_INSTR_SHARED_FLAG = LINK_NI_SYSCALL,
|
|
/* end of instr_t-shared flags */
|
|
/***************************************************/
|
|
|
|
LINK_FRAG_OFFS_AT_END = 0x0800,
|
|
|
|
LINK_END_OF_LIST = 0x1000,
|
|
|
|
LINK_FAKE = 0x2000,
|
|
|
|
LINK_LINKED = 0x4000,
|
|
|
|
LINK_SEPARATE_STUB = 0x8000,
|
|
|
|
/* WARNING: flags field is a ushort, so max flag is 0x8000! */
|
|
};
|
|
|
|
#ifdef UNIX
|
|
# define LINK_NI_SYSCALL_ALL (LINK_NI_SYSCALL | LINK_NI_SYSCALL_INT)
|
|
#else
|
|
# define LINK_NI_SYSCALL_ALL LINK_NI_SYSCALL
|
|
#endif
|
|
|
|
/* linkstub_t heap layout is now quite variable. linkstubs are laid out
|
|
* after the fragment_t structure, which is itself variable.
|
|
* The indirect_linkstub_t split was case 6468
|
|
* The cbr_fallthrough_linkstub_t split was case 6528
|
|
*
|
|
* fragment_t/trace_t
|
|
* array composed of three different sizes of linkstub_t subclasses:
|
|
* direct_linkstub_t
|
|
* cbr_fallthrough_linkstub_t
|
|
* indirect_linkstub_t
|
|
* post_linkstub_t
|
|
*
|
|
* There are three types of specially-supported basic blocks that
|
|
* have no post_linkstub_t:
|
|
*
|
|
* fragment_t
|
|
* indirect_linkstub_t
|
|
*
|
|
* fragment_t
|
|
* direct_linkstub_t
|
|
* direct_linkstub_t
|
|
*
|
|
* fragment_t
|
|
* direct_linkstub_t
|
|
* cbr_fallthrough_linkstub_t
|
|
*/
|
|
|
|
/* To save memory, we have three types of linkstub structs: direct,
|
|
* cbr_fallthrough, and indirect. They each contain the flags field
|
|
* at the same offset, so this struct can be used as a superclass.
|
|
*/
|
|
struct _linkstub_t {
|
|
ushort flags; /* contains LINK_ flags above */
|
|
|
|
/* We limit all fragment bodies to USHRT_MAX size
|
|
* thus we can save space by making the branch ptr a ushort offset.
|
|
* Do not directly access this field -- use EXIT_CTI_PC()
|
|
*/
|
|
ushort cti_offset; /* offset from fragment start_pc of this cti */
|
|
};
|
|
|
|
/* linkage info common to all direct fragment exits */
|
|
typedef struct _common_direct_linkstub_t {
|
|
linkstub_t l;
|
|
|
|
/* outgoing stubs of a fragment never change, and are allocated in
|
|
* an array, but we walk them like a linked list since we don't want
|
|
* to waste space storing the count and all of our access patterns
|
|
* want to touch them all anyway.
|
|
* use LINKSTUB_NEXT_EXIT() to access the next, and LINKSTUB_FINAL()
|
|
* to test if the current guy is the final.
|
|
*
|
|
* Incoming stubs do change and we use this field to chain them:
|
|
*/
|
|
linkstub_t *next_incoming;
|
|
|
|
#ifdef TRACE_HEAD_CACHE_INCR
|
|
/* for linking to trace head, we store the actual fragment_t target.
|
|
* if the target is deleted the link will be unlinked, preventing
|
|
* a stale fragment_t* pointer from sitting around
|
|
*/
|
|
fragment_t *target_fragment;
|
|
#endif
|
|
} common_direct_linkstub_t;
|
|
|
|
/* linkage info for each direct fragment exit */
|
|
typedef struct _direct_linkstub_t {
|
|
common_direct_linkstub_t cdl;
|
|
|
|
/* tag identifying the intended app target of the exit branch
|
|
* Do not directly access this field -- use EXIT_TARGET_TAG(), which
|
|
* works for all linkstub types.
|
|
*/
|
|
app_pc target_tag;
|
|
|
|
/* Must be absolute pc b/c we relocate some stubs away from fragment body.
|
|
* Do not directly access this field -- use EXIT_STUB_PC(), which
|
|
* works for all linkstub types.
|
|
*/
|
|
cache_pc stub_pc;
|
|
} direct_linkstub_t;
|
|
|
|
/* linkage info for cbr fallthrough exits that satisfy two conditions:
|
|
* 1) separate stubs will not be individually freed -- we could
|
|
* have a fancy scheme that frees both at once, but we simply
|
|
* disallow the struct if any freeing will occur.
|
|
* 2) the fallthrough target is within range of a signed short from the
|
|
* owning fragment's start pc (this is typically true even w/ eliding).
|
|
* 3) the fallthrough exit immediately follows the cbr exit.
|
|
* this direct stub split was case 6528.
|
|
*/
|
|
typedef struct _cbr_fallthrough_linkstub_t {
|
|
/* We have no cti_offset as we assume this exit's cti immediately follows
|
|
* the preceding cbr (see conditions above).
|
|
*
|
|
* Our target_tag uses the cti_offset field instead. Since this struct is
|
|
* only used for the 2nd (fallthrough) exit of a cbr whose target
|
|
* is within range for a signed short from the owning fragment_t's tag,
|
|
* we re-use the cti_offset field.
|
|
*
|
|
* This struct is also only used when its exit stub is adjacent to the
|
|
* prior exit's, so we don't need to store stub_pc here.
|
|
*/
|
|
common_direct_linkstub_t cdl;
|
|
} cbr_fallthrough_linkstub_t;
|
|
|
|
/* linkage info for each indirect fragment exit (slit for case 6468) */
|
|
typedef struct _indirect_linkstub_t {
|
|
linkstub_t l;
|
|
} indirect_linkstub_t;
|
|
|
|
/* Data shared among all linkstubs for a particular fragment_t.
|
|
* Kept at the end of the array of linkstubs, and not present for
|
|
* certain common types of fragment_t.
|
|
*/
|
|
typedef struct _post_linkstub_t {
|
|
/* fragment_t + linkstub_t heap size cannot exceed the maximum fragment
|
|
* body size since max sizeof linkstub_t-subclass (16) < min sizeof
|
|
* exit stub (15) + corresponding cti (at least 2). Thus we can
|
|
* use a ushort here, paving the way for an additional field in
|
|
* the future (though right now the other 2 bytes are wasted as
|
|
* this struct is aligned to 4 bytes ).
|
|
*/
|
|
ushort fragment_offset;
|
|
/* We force the compiler to maintain our 4-byte-alignment for heap allocations.
|
|
* XXX: should we support un-aligned in non-special heaps?
|
|
* or could use special heap if we really wanted to save this 2 bytes.
|
|
* also see case 6518 for a way to use this for Traces.
|
|
*/
|
|
ushort padding;
|
|
} post_linkstub_t;
|
|
|
|
/* For chaining together a list of inter-coarse-unit incoming stubs. To
|
|
* eliminate the need for wrappers for a series of fine-grained linkstubs, we
|
|
* directly chain those -- so when walking, walk a fine entry's linkstubs
|
|
* completely before going to the next coarse_incoming_t entry.
|
|
*/
|
|
typedef struct _coarse_incoming_t {
|
|
union {
|
|
cache_pc stub_pc;
|
|
linkstub_t *fine_l;
|
|
} in;
|
|
bool coarse;
|
|
struct _coarse_incoming_t *next;
|
|
} coarse_incoming_t;
|
|
|
|
/* this one does not take in flags b/c historically we used other fields */
|
|
#define LINKSTUB_FAKE(l) (TESTANY(LINK_FAKE, (l)->flags))
|
|
/* direct includes normal direct and cbr fallthrough */
|
|
#define LINKSTUB_DIRECT(flags) (TESTANY(LINK_DIRECT, (flags)))
|
|
#define LINKSTUB_NORMAL_DIRECT(flags) \
|
|
(TESTANY(LINK_DIRECT, (flags)) && !TESTANY(LINK_INDIRECT, (flags)))
|
|
#define LINKSTUB_INDIRECT(flags) \
|
|
(!TESTANY(LINK_DIRECT, (flags)) && TESTANY(LINK_INDIRECT, (flags)))
|
|
#define LINKSTUB_CBR_FALLTHROUGH(flags) \
|
|
(TESTANY(LINK_DIRECT, (flags)) && TESTANY(LINK_INDIRECT, (flags)))
|
|
|
|
/* used with both LINK_* and INSTR_*_EXIT flags */
|
|
#define EXIT_IS_CALL(flags) (TESTANY(LINK_CALL, flags) && !TESTANY(LINK_JMP, flags))
|
|
#define EXIT_IS_JMP(flags) (TESTANY(LINK_JMP, flags) && !TESTANY(LINK_CALL, flags))
|
|
#define EXIT_IS_IND_JMP_PLT(flags) (TESTALL(LINK_JMP | LINK_CALL, flags))
|
|
|
|
#define LINKSTUB_FINAL(l) (TESTANY(LINK_END_OF_LIST, (l)->flags))
|
|
|
|
/* We assume this combination of flags is unique for coarse proxies. */
|
|
#define LINKSTUB_COARSE_PROXY(flags) \
|
|
(TESTALL(LINK_FAKE | LINK_DIRECT | LINK_SEPARATE_STUB, (flags)))
|
|
|
|
/* could optimize to avoid redundant tests */
|
|
#define LINKSTUB_SIZE(l) \
|
|
(LINKSTUB_NORMAL_DIRECT((l)->flags) \
|
|
? sizeof(direct_linkstub_t) \
|
|
: (LINKSTUB_INDIRECT((l)->flags) ? sizeof(indirect_linkstub_t) \
|
|
: (LINKSTUB_CBR_FALLTHROUGH((l)->flags) \
|
|
? sizeof(cbr_fallthrough_linkstub_t) \
|
|
: sizeof(linkstub_t))))
|
|
|
|
#define LINKSTUB_NEXT_EXIT(l) \
|
|
((LINKSTUB_FINAL((l))) ? NULL : ((linkstub_t *)(((byte *)(l)) + LINKSTUB_SIZE(l))))
|
|
|
|
/* we pay the cost of the check in release builds to have the
|
|
* safety return value of NULL
|
|
*/
|
|
#define LINKSTUB_NEXT_INCOMING(l) \
|
|
(LINKSTUB_NORMAL_DIRECT((l)->flags) \
|
|
? ((linkstub_t *)(((direct_linkstub_t *)(l))->cdl.next_incoming)) \
|
|
: (LINKSTUB_CBR_FALLTHROUGH((l)->flags) \
|
|
? ((linkstub_t *)(((cbr_fallthrough_linkstub_t *)(l)) \
|
|
->cdl.next_incoming)) \
|
|
: (ASSERT(false && "indirect linkstub has no next_incoming"), \
|
|
((linkstub_t *)NULL))))
|
|
|
|
/* if sharing a stub then no offs, else offs to get to subsequent stub */
|
|
#define CBR_FALLTHROUGH_STUB_OFFS(f) \
|
|
(INTERNAL_OPTION(cbr_single_stub) ? 0 : DIRECT_EXIT_STUB_SIZE((f)->flags))
|
|
|
|
#define EXIT_CTI_PC_HELPER(f, l) \
|
|
(ASSERT(LINKSTUB_NORMAL_DIRECT((l)->flags)), ((f)->start_pc + (l)->cti_offset))
|
|
|
|
#define EXIT_CTI_PC(f, l) \
|
|
(LINKSTUB_CBR_FALLTHROUGH((l)->flags) \
|
|
? (cbr_fallthrough_exit_cti(EXIT_CTI_PC_HELPER(f, FRAGMENT_EXIT_STUBS(f)))) \
|
|
: ((f)->start_pc + (l)->cti_offset))
|
|
|
|
#define EXIT_STUB_PC_HELPER(dc, f, l) \
|
|
(ASSERT(LINKSTUB_NORMAL_DIRECT((l)->flags)), (((direct_linkstub_t *)(l))->stub_pc))
|
|
|
|
#define EXIT_STUB_PC(dc, f, l) \
|
|
(LINKSTUB_NORMAL_DIRECT((l)->flags) \
|
|
? (((direct_linkstub_t *)(l))->stub_pc) \
|
|
: (LINKSTUB_CBR_FALLTHROUGH((l)->flags) \
|
|
? (EXIT_STUB_PC_HELPER(dc, f, FRAGMENT_EXIT_STUBS(f)) + \
|
|
CBR_FALLTHROUGH_STUB_OFFS(f)) \
|
|
: indirect_linkstub_stub_pc(dc, f, l)))
|
|
|
|
#define EXIT_TARGET_TAG(dc, f, l) \
|
|
(LINKSTUB_NORMAL_DIRECT((l)->flags) \
|
|
? (((direct_linkstub_t *)(l))->target_tag) \
|
|
: (LINKSTUB_CBR_FALLTHROUGH((l)->flags) ? ((f)->tag + ((short)(l)->cti_offset)) \
|
|
: indirect_linkstub_target(dc, f, l)))
|
|
|
|
#ifdef WINDOWS
|
|
# define EXIT_TARGETS_SHARED_SYSCALL(flags) \
|
|
(DYNAMO_OPTION(shared_syscalls) && \
|
|
!TESTANY(LINK_RETURN | LINK_CALL | LINK_JMP, (flags)))
|
|
#else
|
|
# define EXIT_TARGETS_SHARED_SYSCALL(flags) (false)
|
|
#endif
|
|
|
|
/* indirect exits w/o inlining have no stub at all for -no_indirect_stubs */
|
|
#define EXIT_HAS_STUB(l_flags, f_flags) \
|
|
(DYNAMO_OPTION(indirect_stubs) || !LINKSTUB_INDIRECT((l_flags)) || \
|
|
(!EXIT_TARGETS_SHARED_SYSCALL(l_flags) && \
|
|
((DYNAMO_OPTION(inline_trace_ibl) && TESTANY(FRAG_IS_TRACE, (f_flags))) || \
|
|
(DYNAMO_OPTION(inline_bb_ibl) && !TESTANY(FRAG_IS_TRACE, (f_flags))))))
|
|
|
|
/* two cases with no local stub: a separate stub or no stub at all */
|
|
#define EXIT_HAS_LOCAL_STUB(l_flags, f_flags) \
|
|
(EXIT_HAS_STUB(l_flags, f_flags) && !TESTANY(LINK_SEPARATE_STUB, (l_flags)))
|
|
|
|
void
|
|
d_r_link_init(void);
|
|
void
|
|
d_r_link_exit(void);
|
|
void
|
|
link_reset_init(void);
|
|
void
|
|
link_reset_free(void);
|
|
void
|
|
link_thread_init(dcontext_t *dcontext);
|
|
void
|
|
link_thread_exit(dcontext_t *dcontext);
|
|
|
|
/* coarse-grain support */
|
|
|
|
cache_pc
|
|
coarse_stubs_create(coarse_info_t *info, cache_pc pc, size_t size);
|
|
|
|
void
|
|
coarse_stubs_delete(coarse_info_t *info);
|
|
|
|
uint
|
|
coarse_stub_alignment(coarse_info_t *info);
|
|
|
|
void
|
|
coarse_mark_trace_head(dcontext_t *dcontext, fragment_t *f, coarse_info_t *info,
|
|
cache_pc stub, cache_pc body);
|
|
|
|
void
|
|
coarse_unit_unlink(dcontext_t *dcontext, coarse_info_t *info);
|
|
|
|
void
|
|
coarse_unit_unlink_outgoing(dcontext_t *dcontext, coarse_info_t *info);
|
|
|
|
#ifdef DEBUG
|
|
bool
|
|
coarse_unit_outgoing_linked(dcontext_t *dcontext, coarse_info_t *info);
|
|
#endif
|
|
|
|
cache_pc
|
|
coarse_stub_lookup_by_target(dcontext_t *dcontext, coarse_info_t *info,
|
|
cache_pc target_tag);
|
|
|
|
void
|
|
coarse_lazy_link(dcontext_t *dcontext, fragment_t *targetf);
|
|
|
|
cache_pc
|
|
fcache_return_coarse_prefix(cache_pc stub_pc, coarse_info_t *info /*OPTIONAL*/);
|
|
|
|
cache_pc
|
|
trace_head_return_coarse_prefix(cache_pc stub_pc, coarse_info_t *info /*OPTIONAL*/);
|
|
|
|
cache_pc
|
|
get_coarse_ibl_prefix(dcontext_t *dcontext, cache_pc stub_pc,
|
|
ibl_branch_type_t branch_type);
|
|
|
|
bool
|
|
in_coarse_stubs(cache_pc pc);
|
|
|
|
bool
|
|
in_coarse_stub_prefixes(cache_pc pc);
|
|
|
|
cache_pc
|
|
coarse_deref_ibl_prefix(dcontext_t *dcontext, cache_pc target);
|
|
|
|
coarse_info_t *
|
|
get_stub_coarse_info(cache_pc pc);
|
|
|
|
/* Initializes an array of linkstubs beginning with first */
|
|
void
|
|
linkstubs_init(linkstub_t *first, int num_direct, int num_indirect, fragment_t *f);
|
|
|
|
bool
|
|
is_linkable(dcontext_t *dcontext, fragment_t *from_f, linkstub_t *l, fragment_t *targetf,
|
|
bool have_link_lock, bool mark_new_trace_head);
|
|
|
|
uint
|
|
linkstub_size(dcontext_t *dcontext, fragment_t *f, linkstub_t *l);
|
|
|
|
uint
|
|
linkstub_propagatable_flags(uint flags);
|
|
|
|
bool
|
|
linkstub_frag_offs_at_end(uint flags, int direct_exits, int indirect_exits);
|
|
|
|
bool
|
|
use_cbr_fallthrough_short(uint flags, int direct_exits, int indirect_exits);
|
|
|
|
uint
|
|
linkstubs_heap_size(uint flags, int direct_exits, int indirect_exits);
|
|
|
|
fragment_t *
|
|
linkstub_fragment(dcontext_t *dcontext, linkstub_t *l);
|
|
|
|
#ifdef X64
|
|
/* Converts the canonical empty fragment to an empty fragment marked FRAG_32_BIT */
|
|
fragment_t *
|
|
empty_fragment_mark_x86(fragment_t *f);
|
|
#endif
|
|
|
|
#ifdef DEBUG
|
|
bool
|
|
linkstub_owned_by_fragment(dcontext_t *dcontext, fragment_t *f, linkstub_t *l);
|
|
#endif
|
|
|
|
void
|
|
set_last_exit(dcontext_t *dcontext, linkstub_t *l);
|
|
void
|
|
last_exit_deleted(dcontext_t *dcontext);
|
|
void
|
|
set_coarse_ibl_exit(dcontext_t *dcontext);
|
|
int
|
|
get_last_linkstub_ordinal(dcontext_t *dcontext);
|
|
|
|
linkstub_t *
|
|
get_deleted_linkstub(dcontext_t *dcontext);
|
|
const linkstub_t *
|
|
get_starting_linkstub(void);
|
|
const linkstub_t *
|
|
get_reset_linkstub(void);
|
|
const linkstub_t *
|
|
get_syscall_linkstub(void);
|
|
const linkstub_t *
|
|
get_selfmod_linkstub(void);
|
|
#ifdef AARCH64
|
|
/* On AArch64 we need to refer to linkstub_selfmod from aarch64.asm. */
|
|
extern const linkstub_t linkstub_selfmod;
|
|
#endif
|
|
const linkstub_t *
|
|
get_ibl_deleted_linkstub(void);
|
|
/* This is used for Windows APC, callback, etc. and Linux sigreturn, forge fault, etc. */
|
|
const linkstub_t *
|
|
get_asynch_linkstub(void);
|
|
const linkstub_t *
|
|
get_native_exec_linkstub(void);
|
|
const linkstub_t *
|
|
get_native_exec_syscall_linkstub(void);
|
|
#ifdef HOT_PATCHING_INTERFACE
|
|
const linkstub_t *
|
|
get_hot_patch_linkstub(void);
|
|
#endif
|
|
const linkstub_t *
|
|
get_client_linkstub(void);
|
|
const linkstub_t *
|
|
get_special_ibl_linkstub(ibl_branch_type_t ibl_type, bool is_trace);
|
|
const linkstub_t *
|
|
get_ibl_sourceless_linkstub(uint link_flags, uint frag_flags);
|
|
bool
|
|
is_ibl_sourceless_linkstub(const linkstub_t *l);
|
|
const linkstub_t *
|
|
get_coarse_exit_linkstub(void);
|
|
const linkstub_t *
|
|
get_coarse_trace_head_exit_linkstub(void);
|
|
|
|
#define IS_COARSE_LINKSTUB(l) \
|
|
((l) == get_coarse_exit_linkstub() || (l) == get_coarse_trace_head_exit_linkstub())
|
|
|
|
#ifdef WINDOWS
|
|
const linkstub_t *
|
|
get_shared_syscalls_unlinked_linkstub(void);
|
|
# define IS_SHARED_SYSCALLS_UNLINKED_LINKSTUB(l) \
|
|
((l) == get_shared_syscalls_unlinked_linkstub())
|
|
|
|
const linkstub_t *
|
|
get_shared_syscalls_trace_linkstub(void);
|
|
const linkstub_t *
|
|
get_shared_syscalls_bb_linkstub(void);
|
|
# define IS_SHARED_SYSCALLS_LINKSTUB(l) \
|
|
((l) == get_shared_syscalls_trace_linkstub() || \
|
|
(l) == get_shared_syscalls_bb_linkstub() || \
|
|
(l) == get_shared_syscalls_unlinked_linkstub())
|
|
# define IS_SHARED_SYSCALLS_TRACE_LINKSTUB(l) \
|
|
((l) == get_shared_syscalls_trace_linkstub())
|
|
#else
|
|
# define IS_SHARED_SYSCALLS_UNLINKED_LINKSTUB(l) false
|
|
# define IS_SHARED_SYSCALLS_LINKSTUB(l) false
|
|
# define IS_SHARED_SYSCALLS_TRACE_LINKSTUB(l) false
|
|
#endif
|
|
|
|
#ifdef LINUX_KERNEL
|
|
const linkstub_t *
|
|
get_syscall_entry_linkstub(void);
|
|
const linkstub_t *
|
|
get_user_interrupt_entry_linkstub(void);
|
|
# define IS_KERNEL_ENTRY_LINKSTUB(l) \
|
|
((l) == get_syscall_entry_linkstub() || \
|
|
(l) == get_user_interrupt_entry_linkstub())
|
|
#endif
|
|
|
|
bool
|
|
should_separate_stub(dcontext_t *dcontext, app_pc target, uint fragment_flags);
|
|
int
|
|
local_exit_stub_size(dcontext_t *dcontext, app_pc target, uint fragment_flags);
|
|
void
|
|
separate_stub_create(dcontext_t *dcontext, fragment_t *f, linkstub_t *l);
|
|
void
|
|
linkstub_free_exitstubs(dcontext_t *dcontext, fragment_t *f);
|
|
|
|
void
|
|
linkstubs_shift(dcontext_t *dcontext, fragment_t *f, ssize_t shift);
|
|
|
|
void
|
|
link_new_fragment(dcontext_t *dcontext, fragment_t *f);
|
|
void
|
|
link_fragment_outgoing(dcontext_t *dcontext, fragment_t *f, bool new_fragment);
|
|
void
|
|
unlink_fragment_outgoing(dcontext_t *dcontext, fragment_t *f);
|
|
void
|
|
link_fragment_incoming(dcontext_t *dcontext, fragment_t *f, bool new_fragment);
|
|
void
|
|
unlink_fragment_incoming(dcontext_t *dcontext, fragment_t *f);
|
|
|
|
void
|
|
shift_links_to_new_fragment(dcontext_t *dcontext, fragment_t *old_f, fragment_t *new_f);
|
|
future_fragment_t *
|
|
incoming_remove_fragment(dcontext_t *dcontext, fragment_t *f);
|
|
|
|
/* if this linkstub shares the stub with the next linkstub, returns the
|
|
* next linkstub; else returns NULL
|
|
*/
|
|
linkstub_t *
|
|
linkstub_shares_next_stub(dcontext_t *dcontext, fragment_t *f, linkstub_t *l);
|
|
|
|
/* Returns the total size needed for stubs if info is frozen. */
|
|
size_t
|
|
coarse_frozen_stub_size(dcontext_t *dcontext, coarse_info_t *info, uint *num_fragments,
|
|
uint *num_stubs);
|
|
|
|
/* Removes any incoming data recording the outgoing link from stub */
|
|
void
|
|
coarse_remove_outgoing(dcontext_t *dcontext, cache_pc stub, coarse_info_t *src_info);
|
|
|
|
void
|
|
coarse_update_outgoing(dcontext_t *dcontext, cache_pc old_stub, cache_pc new_stub,
|
|
coarse_info_t *src_info, bool replace);
|
|
|
|
void
|
|
coarse_unit_shift_links(dcontext_t *dcontext, coarse_info_t *info);
|
|
|
|
/* Updates the info pointers embedded in the coarse_stub_areas vector */
|
|
void
|
|
coarse_stubs_set_info(coarse_info_t *info);
|
|
|
|
/* Sets the final used pc in a frozen stub region */
|
|
void
|
|
coarse_stubs_set_end_pc(coarse_info_t *info, byte *end_pc);
|
|
|
|
#endif /* _CORE_LINK_H_ */
|