Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 19 additions & 11 deletions core/arch/aarchxx/mangle.c
Original file line number Diff line number Diff line change
Expand Up @@ -2149,12 +2149,14 @@ restore_tls_base_to_stolen_reg(dcontext_t *dcontext, instrlist_t *ilist, instr_t
{
/* store app val back if it might be written */
if (instr_writes_to_reg(instr, dr_reg_stolen, DR_QUERY_INCLUDE_COND_DSTS)) {
PRE(ilist, next_instr,
XINST_CREATE_store(dcontext,
opnd_create_base_disp(reg, REG_NULL, 0,
os_tls_offset(TLS_REG_STOLEN_SLOT),
OPSZ_PTR),
opnd_create_reg(dr_reg_stolen)));
instr_t *store = XINST_CREATE_store(
dcontext,
opnd_create_base_disp(reg, REG_NULL, 0, os_tls_offset(TLS_REG_STOLEN_SLOT),
OPSZ_PTR),
opnd_create_reg(dr_reg_stolen));
instr_set_our_mangling(store, true);
instr_set_our_mangling_epilogue(store, true);
PRE(ilist, next_instr, store);
} else {
DOLOG(4, LOG_INTERP, {
LOG(THREAD, LOG_INTERP, 4, "skip save stolen reg app value for: ");
Expand All @@ -2164,9 +2166,11 @@ restore_tls_base_to_stolen_reg(dcontext_t *dcontext, instrlist_t *ilist, instr_t
}
/* restore stolen reg from spill reg */
/* This precise opcode (OP_orr) is checked for in instr_is_stolen_reg_move(). */
PRE(ilist, next_instr,
XINST_CREATE_move(dcontext, opnd_create_reg(dr_reg_stolen),
opnd_create_reg(reg)));
instr_t *move =
XINST_CREATE_move(dcontext, opnd_create_reg(dr_reg_stolen), opnd_create_reg(reg));
instr_set_our_mangling(move, true);
instr_set_our_mangling_epilogue(move, true);
PRE(ilist, next_instr, move);
}

/* Mangle simple dr_reg_stolen access.
Expand Down Expand Up @@ -2234,8 +2238,12 @@ mangle_stolen_reg(dcontext_t *dcontext, instrlist_t *ilist, instr_t *instr,
/* restore tls_base back to dr_reg_stolen */
restore_tls_base_to_stolen_reg(dcontext, ilist, instr, next_instr, tmp, slot);
/* restore tmp if necessary */
if (should_restore)
PRE(ilist, next_instr, instr_create_restore_from_tls(dcontext, tmp, slot));
if (should_restore) {
instr_t *restore = instr_create_restore_from_tls(dcontext, tmp, slot);
instr_set_our_mangling(restore, true);
instr_set_our_mangling_epilogue(restore, true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A translation needs to be set as well: it's assumed by the epilogue handling code.
instrlist_set_translation_target() is typically already set: should point to the app instr.
Yet don't we want it to be the post-app-instr for the epilogue?
Use instr_set_translation_mangling_epilogue()?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the translation gets set later by d_r_mangle(), and it's set to the current instr rather than the following one, which I think is probably what developers would expect in the absence of a clear statement to the contrary.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The current instr is incorrect for post-instr mangling: the translation PC is the PC to be re-started. It can't be a retired instr as it is incorrect to re-execute it.

PRE(ilist, next_instr, restore);
}
}

/* replace thread register read instruction with a TLS load instr */
Expand Down
74 changes: 72 additions & 2 deletions core/translate.c
Original file line number Diff line number Diff line change
Expand Up @@ -266,8 +266,6 @@ instr_is_load_mcontext_base(instr_t *inst)

#ifdef X86

/* XXX i#3329: add support for ARM/AArch64. */

static bool
translate_walk_enters_mangling_epilogue(dcontext_t *tdcontext, instr_t *inst,
translate_walk_t *walk)
Expand Down Expand Up @@ -930,6 +928,68 @@ recreate_app_state_from_info(dcontext_t *tdcontext, const translation_info_t *in
return res;
}

#ifdef AARCH64 /* XXX: Add other non-x86 architectures here? */
/* Emulate instructions in mangling epilogue. */
static void
emulate_epilogue(priv_mcontext_t *mc, instr_t *first_inst)
{
app_pc translation = first_inst->translation;
for (instr_t *inst = first_inst;
inst != NULL && instr_is_our_mangling_epilogue(inst) &&
instr_get_translation(inst) == translation;
inst = instr_get_next(inst)) {
switch (instr_get_opcode(inst)) {
case OP_ldr: {
ASSERT(instr_num_dsts(inst) == 1 && instr_num_srcs(inst) == 1);
opnd_t dst = instr_get_dst(inst, 0);
opnd_t src = instr_get_src(inst, 0);
ASSERT(opnd_is_reg(dst) && opnd_is_base_disp(src));
reg_t rd = opnd_get_reg(dst);
ASSERT(DR_REG_X0 <= rd && rd <= DR_REG_X30);
reg_t value;
memcpy(&value, opnd_compute_address_priv(src, mc), sizeof(value));
reg_set_value_priv(rd, mc, value);
break;
}
case OP_orr: {
ASSERT(instr_num_dsts(inst) == 1 && instr_num_srcs(inst) == 4);
opnd_t dst = instr_get_dst(inst, 0);
opnd_t src1 = instr_get_src(inst, 0);
opnd_t src2 = instr_get_src(inst, 1);
opnd_t src3 = instr_get_src(inst, 2);
opnd_t src4 = instr_get_src(inst, 3);
(void)src1;
(void)src3;
(void)src4;
ASSERT(opnd_is_reg(dst) && opnd_is_reg(src1) && opnd_is_reg(src2) &&
opnd_is_immed(src3) && opnd_is_immed(src4));
ASSERT(opnd_get_reg(src1) == DR_REG_XZR);
ASSERT(opnd_get_immed_int(src3) == DR_SHIFT_LSL);
ASSERT(opnd_get_immed_int(src4) == 0);
reg_t rd = opnd_get_reg(dst);
reg_t rs = opnd_get_reg(src2);
ASSERT(DR_REG_X0 <= rd && rd <= DR_REG_X30 && DR_REG_X0 <= rs &&
rs <= DR_REG_X30);
reg_set_value_priv(rd, mc, reg_get_value_priv(rs, mc));
break;
}
case OP_str: {
ASSERT(instr_num_dsts(inst) == 1 && instr_num_srcs(inst) == 1);
opnd_t dst = instr_get_dst(inst, 0);
opnd_t src = instr_get_src(inst, 0);
ASSERT(opnd_is_base_disp(dst) && opnd_is_reg(src));
reg_t rs = opnd_get_reg(src);
ASSERT(DR_REG_X0 <= rs && rs <= DR_REG_X30);
reg_t value = reg_get_value_priv(rs, mc);
memcpy(opnd_compute_address_priv(dst, mc), &value, sizeof(value));
break;
}
default: ASSERT(false && "emulate_epilogue unimplemented instr");
}
}
}
#endif /* AARCH64 */

/* Returns a success code, but makes a best effort regardless.
* If just_pc is true, only recreates pc.
* Modifies mc with the recreated state.
Expand Down Expand Up @@ -1127,6 +1187,14 @@ recreate_app_state_from_ilist(dcontext_t *tdcontext, instrlist_t *ilist, byte *s
}
}
}
#ifdef AARCH64 /* XXX: Add other non-x86 architectures here? */
if (instr_is_our_mangling_epilogue(inst)) {
if (!just_pc)
emulate_epilogue(mc, inst);
mc->pc = answer + 4;
return res;
}
#endif
if (!just_pc)
translate_walk_restore(tdcontext, &walk, inst, answer);
answer = translate_restore_special_cases(tdcontext, answer);
Expand Down Expand Up @@ -1962,6 +2030,7 @@ record_translation_info(dcontext_t *dcontext, fragment_t *f, instrlist_t *existi
void
stress_test_recreate_state(dcontext_t *dcontext, fragment_t *f, instrlist_t *ilist)
{
# ifndef AARCH64 /* XXX: Update this test for AArch64. */
priv_mcontext_t mc;
bool res;
cache_pc cpc;
Expand Down Expand Up @@ -2082,6 +2151,7 @@ stress_test_recreate_state(dcontext_t *dcontext, fragment_t *f, instrlist_t *ili
if (TEST(FRAG_IS_TRACE, f->flags)) {
instrlist_clear_and_destroy(dcontext, ilist);
}
# endif /* AARCH64 */
}
#endif /* INTERNAL */

Expand Down
6 changes: 6 additions & 0 deletions suite/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6081,6 +6081,12 @@ if (UNIX)
if (LINUX)
tobuild(linux.brk linux/brk.cpp)
endif ()
# Test translation of mangling epilogue.
# XXX: Port to other (non-x86) architectures.
if (LINUX AND NOT ANDROID AND AARCH64)
tobuild(linux.sigtrans linux/sigtrans.c)
target_link_libraries(linux.sigtrans rt)
endif ()
else (UNIX)
add_exe(win32.infloop win32/infloop.c)
add_exe(win32.attachee win32/attachee.c)
Expand Down
65 changes: 11 additions & 54 deletions suite/tests/linux/signal_pre_syscall.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@

#ifndef ASM_CODE_ONLY /* C code */

# include "tools.h"

# include <signal.h>
# include <stdio.h>
# include <stdbool.h>
# include <stdlib.h>
# include <string.h>
# include <time.h>
Expand Down Expand Up @@ -73,9 +75,11 @@ handler(int signum, siginfo_t *info, void *ucontext)
* signal will never appear to have happened during the critical block
* because we delay the delivery of async signals to the end of the block.
*/
int
try(timer_t timer, unsigned long long timer_duration_ns)
bool
try(int *adjust, unsigned long long timer_duration_ns, void *arg)
{
timer_t timer = *(timer_t *)arg;

flag_dst = 1;
flag_src = -1;

Expand All @@ -93,7 +97,8 @@ try(timer_t timer, unsigned long long timer_duration_ns)
if (timer_settime(timer, 0, &spec0, NULL))
fail("timer_settime");

return flag_dst;
*adjust = flag_dst;
return *adjust == 0;
}

int
Expand All @@ -116,57 +121,9 @@ main(int argc, char *argv[])
if (timer_create(CLOCK_MONOTONIC, &sevp, &timer))
fail("timer_create");

/* Repeatedly call try(), changing timer_duration_ns each time.
* Typically we halve the step each time, which results in a
* binary search, but if we have had the same result several times
* in succession then we suspect that something has changed so we
* start doubling the step instead.
*/
unsigned long long timer_duration_ns = 1024; /* arbitrary initial value */
unsigned long long step = 1024; /* power of two */
int result = -1;
unsigned long long unchanged_results = 0;
/* A thousand tries took a few seconds and gave a few hundred hits
* when tested on current hardware.
*/
for (int i = 0; i < 1000; i++) {
int previous_result = result;
result = try(timer, timer_duration_ns);

/* Stop trying if the signal arrived during the critical block.
* This never happens (or seems never to happen) under DynamoRIO.
*/
if (result == 0)
break;

/* Update unchanged_results. */
if (result == previous_result)
++unchanged_results;
else
unchanged_results = 0;

/* Update step. */
if (unchanged_results < 5)
step = step / 2 > 0 ? step / 2 : step;
else
step = step * 2 > 0 ? step * 2 : step;

/* Adjust timer_duration_ns for next try. */
if (result < 0)
timer_duration_ns = timer_duration_ns + step > timer_duration_ns
? timer_duration_ns + step
: (unsigned long long)-1;
else {
if (timer_duration_ns > step)
timer_duration_ns -= step;
else {
timer_duration_ns = 1;
step = 1;
}
}
}
adaptive_retry(try, 1000, 1024, &timer, true);

printf("all done\n");
print("all done\n");
return 0;
}

Expand Down
Loading
Loading