Created
July 30, 2014 13:21
-
-
Save pgoodman/12961865dfa261e30e1e to your computer and use it in GitHub Desktop.
Trace logger in Granary+
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Print $arg1 instructions starting at address $arg0. | |
define pi | |
set $__rip = $arg0 | |
set $__ni = $arg1 | |
python None ; \ | |
rip = str(gdb.parse_and_eval("$__rip")).lower() ; \ | |
ni = str(gdb.parse_and_eval("$__ni")).lower() ; \ | |
gdb.execute( \ | |
"x/%si %s\n" % (ni, rip), \ | |
from_tty=True, to_string=False) ; | |
end | |
# Print the $arg0th most recent entry in the trace log, where 0 is the | |
# most recent log entry. | |
# | |
# An optional second parameter can be specified, which is the number of | |
# instructions to disassemble from the traced block. | |
define pt | |
set $__i = granary_trace_log_index + GRANARY_TRACE_LOG_LENGTH - $arg0 | |
set $__i = ($__i) % GRANARY_TRACE_LOG_LENGTH | |
set $__r = &(granary_trace_log[$__i]) | |
# Adjust the instruction pointer for the size of `lea rsp, [rsp +- 128]`, but | |
# only in user space (where redzone protection is needed). | |
set $__rip = $__r->rip | |
if $in_user_space | |
set $__rip = $__rip + 8 | |
end | |
# Print the regs state. | |
printf "Trace Log Entry %d\n", $arg0 | |
printf " r15 = %#18lx r14 = %#18lx\n", $__r->r15, $__r->r14 | |
printf " r13 = %#18lx r12 = %#18lx\n", $__r->r13, $__r->r12 | |
printf " r11 = %#18lx r10 = %#18lx\n", $__r->r11, $__r->r10 | |
printf " r9 = %#18lx r9 = %#18lx\n", $__r->r9, $__r->r8 | |
printf " rdi = %#18lx rsi = %#18lx\n", $__r->rdi, $__r->rsi | |
printf " rbp = %#18lx rbx = %#18lx\n", $__r->rbp, $__r->rbx | |
printf " rdx = %#18lx rcx = %#18lx\n", $__r->rdx, $__r->rcx | |
printf " rax = %#18lx rip = %#18lx\n", $__r->rax, $__rip | |
printf " flags =" | |
# Print the flags state. | |
if $__r->rflags & (1 << 0) | |
printf " CF" | |
end | |
if $__r->rflags & (1 << 2) | |
printf " PF" | |
end | |
if $__r->rflags & (1 << 4) | |
printf " AF" | |
end | |
if $__r->rflags & (1 << 6) | |
printf " ZF" | |
end | |
if $__r->rflags & (1 << 7) | |
printf " SF" | |
end | |
if $__r->rflags & (1 << 8) | |
printf " TF" | |
end | |
if $__r->rflags & (1 << 9) | |
printf " IF" | |
end | |
if $__r->rflags & (1 << 10) | |
printf " DF" | |
end | |
if $__r->rflags & (1 << 11) | |
printf " OF" | |
end | |
if $__r->rflags & (1 << 13) | |
printf " NT" | |
end | |
if $__r->rflags & (1 << 16) | |
printf " RF" | |
end | |
printf "\n" | |
if $argc == 2 | |
printf "\nFirst %d instructions:\n", $arg1 | |
pi $__rip $arg1 | |
end | |
dont-repeat | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(gdb) pt 0 10 | |
Trace log entry 0 | |
r15 = 0x3c6ef372 r14 = 0x27999da8 | |
r13 = 0x1f83d9ab r12 = 0x7f23066d7060 | |
r11 = 0x7f23083a5630 r10 = 0x510e527f | |
r9 = 0xbb67ae85 r9 = 0x6a09e667 | |
rdi = 0x3a6fe667 rsi = 0x7f23083a5900 | |
rbp = 0x9b05688c rbx = 0xf377ed68 | |
rdx = 0x98c7e2a2 rcx = 0xfc08884d | |
rax = 0x4 rip = 0x7f2305261618 | |
flags = CF SF IF | |
First 10 instructions: | |
0x7f2305261618: mov QWORD PTR fs:0xfffffffffffffef8,r12 | |
0x7f2305261621: mov r12,rax | |
0x7f2305261624: lahf | |
0x7f2305261625: seto al | |
0x7f2305261628: xchg r12,rax | |
0x7f230526162a: mov r14d,r13d | |
0x7f230526162d: mov r13d,ebp | |
0x7f2305261630: mov ebp,r10d | |
0x7f2305261633: mov r10d,edx | |
0x7f2305261636: mov edx,r15d | |
(gdb) pt 1 | |
Trace Log Entry 1 | |
r15 = 0x3c6ef372 r14 = 0x5be0cd19 | |
r13 = 0x1f83d9ab r12 = 0x7f23066d7060 | |
r11 = 0x7f23083a5630 r10 = 0x510e527f | |
r9 = 0xbb67ae85 r9 = 0x6a09e667 | |
rdi = 0x7f23083a5608 rsi = 0x7f23083a5900 | |
rbp = 0x9b05688c rbx = 0x5be0cd19 | |
rdx = 0xa54ff53a rcx = 0x1f83d9ab | |
rax = 0 rip = 0x7f2305260d40 | |
flags = PF ZF IF | |
(gdb) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Copyright 2014 Peter Goodman, all rights reserved. */ | |
#include "granary/arch/x86-64/asm/include.asm.inc" | |
START_FILE | |
DECLARE_FUNC(granary_trace_block_regs) | |
DEFINE_FUNC(granary_trace_block) | |
// Saved IP is already on the stack in the form of the return address. | |
push %rax | |
push %rcx | |
push %rdx | |
push %rbx | |
push %rbp | |
push %rsi | |
push %rdi | |
push %r8 | |
push %r9 | |
push %r10 | |
push %r11 | |
push %r12 | |
push %r13 | |
push %r14 | |
push %r15 | |
pushfq | |
lea (%rsp), %rdi; | |
GRANARY_IF_KERNEL( cli ) // Disable interrupts. | |
call granary_trace_block_regs | |
popfq | |
pop %r15 | |
pop %r14 | |
pop %r13 | |
pop %r12 | |
pop %r11 | |
pop %r10 | |
pop %r9 | |
pop %r8 | |
pop %rdi | |
pop %rsi | |
pop %rbp | |
pop %rbx | |
pop %rdx | |
pop %rcx | |
pop %rax | |
ret | |
END_FUNC(granary_trace_block) | |
END_FILE |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Copyright 2014 Peter Goodman, all rights reserved. */ | |
#define GRANARY_INTERNAL | |
#define GRANARY_ARCH_INTERNAL | |
#include "granary/arch/x86-64/builder.h" | |
#include "granary/base/string.h" | |
#include "granary/code/fragment.h" | |
#include "granary/cache.h" | |
extern "C" { | |
// The entrypoint to the trace log. This is an assemble routine that records | |
// the register state in the form of a `struct RegisterState`, and then passes | |
// it off to `granary_trace_block_regs`. | |
extern void granary_trace_block(void); | |
struct RegisterState { | |
uint64_t rflags; // Last to be pushed. | |
uint64_t r15; | |
uint64_t r14; | |
uint64_t r13; | |
uint64_t r12; | |
uint64_t r11; | |
uint64_t r10; | |
uint64_t r9; | |
uint64_t r8; | |
uint64_t rdi; | |
uint64_t rsi; | |
uint64_t rbp; | |
uint64_t rbx; | |
uint64_t rdx; | |
uint64_t rcx; | |
uint64_t rax; | |
uint64_t rip; // Return address. | |
}; | |
enum { | |
GRANARY_TRACE_LOG_LENGTH = 1024 | |
}; | |
// The recorded entries in the trace. This is a global variable so that GDB | |
// can see it. | |
RegisterState granary_trace_log[GRANARY_TRACE_LOG_LENGTH]; | |
// The index into Granary's trace log. Also a global variable so that GDB can | |
// easily see it. | |
unsigned granary_trace_log_index = 0; | |
// Record an entry in Granary's trace log. | |
void granary_trace_block_regs(const RegisterState *regs) { | |
auto index = __sync_add_and_fetch(&granary_trace_log_index, 1U); | |
auto &log_regs(granary_trace_log[index % GRANARY_TRACE_LOG_LENGTH]); | |
memcpy(&log_regs, regs, sizeof *regs); | |
} | |
} // extern C | |
#define PREP(...) \ | |
do { \ | |
__VA_ARGS__ ; \ | |
frag->instrs.Prepend(new NativeInstruction(&ni)); \ | |
} while (0) | |
namespace granary { | |
namespace arch { | |
// Adds in some extra "tracing" instructions to the beginning of a basic block. | |
void AddBlockTracer(Fragment *frag, BlockMetaData *meta, | |
CachePC estimated_encode_pc) { | |
Instruction ni; | |
if (arch::REDZONE_SIZE_BYTES) { | |
PREP(LEA_GPRv_AGEN(&ni, XED_REG_RSP, BaseDispMemOp(REDZONE_SIZE_BYTES, | |
XED_REG_RSP, | |
ADDRESS_WIDTH_BITS))); | |
} | |
auto encode_addr = reinterpret_cast<uintptr_t>(estimated_encode_pc); | |
auto target_addr = UnsafeCast<uintptr_t>(granary_trace_block); | |
auto target_pc = reinterpret_cast<PC>(target_addr); | |
auto diff = std::max(encode_addr, target_addr) - | |
std::min(encode_addr, target_addr); | |
// TODO(pag): Generalize the following pattern, as in the first Granary. | |
if (diff > 4187593113UL) { // > ~3.9GB away; don't risk it for a rel32. | |
auto cache_meta = MetaDataCast<CacheMetaData *>(meta); | |
auto addr = new NativeAddress(target_pc, &(cache_meta->native_addresses)); | |
PREP(CALL_NEAR_MEMv(&ni, addr)); | |
} else { | |
PREP(CALL_NEAR_RELBRd(&ni, target_pc)); | |
} | |
if (arch::REDZONE_SIZE_BYTES) { | |
PREP(LEA_GPRv_AGEN(&ni, XED_REG_RSP, BaseDispMemOp(-REDZONE_SIZE_BYTES, | |
XED_REG_RSP, | |
ADDRESS_WIDTH_BITS))); | |
} | |
} | |
} // namespace arch | |
} // namespace granary |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment