Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support Non-hook-RET options #21

Closed
ParkHanbum opened this issue Aug 10, 2019 · 0 comments
Closed

support Non-hook-RET options #21

ParkHanbum opened this issue Aug 10, 2019 · 0 comments

Comments

@ParkHanbum
Copy link
Owner

ParkHanbum commented Aug 10, 2019

uftrace hope that functions follow the calling convention. but there is an exception like nodejs case. so, it is added restore-reset mechanism to uftrace. it still needs more precision.

I have two exceptional cases in v8 interpreter that uftrace crashed on.

  1. reuse stack frame
    v8 interpreter check the code objects which exist in javascript stack frame for some purpose. v8 interpreter use its own stack frame because it want to not affect to C stack frame. so, stack base frame does not changed in v8 interpreter logic. in this case, while v8 interpreter check the javascript stack frame, it find weird value mcount_return_fn that has been instrumented by uftrace. and occure crash.

let's see followed case:

d8> 1+1

Thread 2.1 "d8" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff2d90840 (LWP 118815)]
0x00005555555bd9bc in std::__Cr::__loadword<unsigned long> (__p=0x7ffff5580038) at ../../buildtools/third_party/libc++/trunk/include/utility:978
978         std::memcpy(&__r, __p, sizeof(__r));
(gdb) bt
#0  0x00005555555bd9bc in std::__Cr::__loadword<unsigned long> (__p=0x7ffff5580038) at ../../buildtools/third_party/libc++/trunk/include/utility:978
#1  0x00005555555d6ced in v8::base::AsAtomicImpl<long>::Relaxed_Load<unsigned long> (addr=0x7ffff5580038) at ../../src/base/atomic-utils.h:78
#2  0x00005555555d6bed in v8::internal::FullObjectSlot::Relaxed_Load (this=0x7fffffffb840) at ../../src/objects/slots-inl.h:43
#3  0x00007ffff6c0d294 in v8::internal::MemoryChunk::HasHeaderSentinel (slot_addr=140737310097407) at ../../src/heap/spaces-inl.h:209
#4  0x00007ffff6c0d1e5 in v8::internal::MemoryChunk::FromAnyPointerAddress (addr=140737310097407) at ../../src/heap/spaces-inl.h:213
#5  0x00007ffff6c072e1 in v8::internal::PagedSpace::Contains (this=0x55555569b8e0, addr=140737349680485) at ../../src/heap/spaces-inl.h:164
#6  0x00007ffff6bfd305 in v8::internal::Heap::GcSafeFindCodeForInnerPointer (this=0x5555568a8fe8, inner_pointer=140737349680485) at ../../src/heap/heap.cc:5699
#7  0x00007ffff7bbfd65 in __dentry__ () at /home/m/git/uftrace/arch/x86_64/dynamic.S:114
Backtrace stopped: previous frame inner to this frame (corrupt stack?)

v8 interpreter crashed on here:

0x00007ffff6bfd305 in v8::internal::Heap::GcSafeFindCodeForInnerPointer (this=0x5555568a8fe8, inner_pointer=140737349680485) at ../../src/heap/heap.cc:5699
(gdb) p/x inner_pointer
$1 = 0x7ffff7bbfd65
(gdb) x/gx 0x7ffff7bbfd65
0x7ffff7bbfd65 <dynamic_return>:        0x245c894c60ec8348

source codes :

// src/heap/heap.cc:5699
DCHECK(code_space()->Contains(inner_pointer));

v8 interpreter could not found the address of mcount_return_fn from its code object pool, obviously.

this is normal case:

Thread 2.1 "d8" hit Breakpoint 2, v8::internal::StackFrame::ComputeType (iterator=0x7fffffffc1a8, state=0x7fffffffc0c0) at ../../src/frames.cc:502
502           Code code_obj = GetContainingCode(iterator->isolate(), pc);
(gdb) p *state
$1 = {sp = 140737488341616, fp = 140737488341776, pc_address = 0x7fffffffca68, callee_pc_address = 0x0, constant_pool_address = 0x0}
(gdb) p/x *state
$2 = {sp = 0x7fffffffca70, fp = 0x7fffffffcb10, pc_address = 0x7fffffffca68, callee_pc_address = 0x0, constant_pool_address = 0x0}
(gdb) x/gx 0x7fffffffca68
0x7fffffffca68: 0x00007ffff78957b2
(gdb) x/i 0x00007ffff78957b2
   0x7ffff78957b2 <Builtins_LdaGlobalHandler+28146>:    mov    r8,QWORD PTR [rbp-0x30]

see belowed instructions.

Old value = 1143480881
New value = -138674667
0x00007ffff73ac1cc in Builtins_AdaptorWithBuiltinExitFrame () from /home/m/git/v8/v8/out.gn/x64.debug/./libv8.so
(gdb) disas
Dump of assembler code for function Builtins_AdaptorWithBuiltinExitFrame:
   0x00007ffff73ac1ac <+364>:   int3
   0x00007ffff73ac1ad <+365>:   mov    rcx,rax
   0x00007ffff73ac1b0 <+368>:   shl    rcx,0x20
   0x00007ffff73ac1b4 <+372>:   mov    rbp,QWORD PTR [rbp+0x0]
   0x00007ffff73ac1b8 <+376>:   mov    r10,QWORD PTR [rsp+0x18]
   0x00007ffff73ac1bd <+381>:   mov    QWORD PTR [rsp+0x28],r10
   0x00007ffff73ac1c2 <+386>:   mov    r10,QWORD PTR [rsp+0x38]
   0x00007ffff73ac1c7 <+391>:   mov    QWORD PTR [rsp+0x18],r10
=> 0x00007ffff73ac1cc <+396>:   mov    rbx,QWORD PTR [rsp+0x20]

(gdb) p/x $rsp+0x20
$3 = 0x7fffffffcae8

(gdb) call mcount_iterate_mtdp()
WARN: [IDX] [OFFSET] [PARENT_LOC](CURRENT_VALUE) [PARENT_VALUE](STORED) [CHILD]
WARN: [0] [0] 0x7fffffffd238(value:0x5555555c166c)       0x5555555c166c  0x7ffff6542c95
WARN: [1] [54] 0x7fffffffd088(value:0x7ffff6542f23)      0x7ffff6542f23  0x7ffff6b49875
WARN: [2] [20] 0x7fffffffcfe8(value:0x7ffff6b498df)      0x7ffff6b498df  0x7ffff6b498f5
WARN: [3] [112] 0x7fffffffcc68(value:0x7ffff6b4c58c)     0x7ffff6b4c58c  0x7ffff73bdcc5
WARN: [4] [13] 0x7fffffffcc00(value:0x7ffff73bdd38)      0x7ffff73bdd38  0x7ffff73bdf65
WARN: [5] [5] 0x7fffffffcbd8(value:0x7ffff73bdfbd)       0x7ffff73bdfbd  0x7ffff73c85c5
WARN: [6] [9] 0x7fffffffcb90(value:0x7ffff73c8988)       0x7ffff73c8988  0x7ffff73c8a65
WARN: [7] [1] 0x7fffffffcb88(value:0x7ffff7bbfe15)       0x7ffff7bbfe15  0x7ffff73c85c5
WARN: [8] [14] 0x7fffffffcb18(value:0x7ffff73c8988)      0x7ffff73c8988  0x7ffff73c8a65
WARN: [9] [3] 0x7fffffffcb00(value:0x7ffff7bbfe15)       0x7ffff7bbfe15  0x7ffff73ac225
WARN: [10] [0] 0x7fffffffcb00(value:0x7ffff7bbfe15)      0x7ffff7bbfe15  0x7ffff74ef945
WARN: [11] [0] 0x7fffffffcb00(value:0x7ffff7bbfe15)      0x7ffff7bbfe15  0x7ffff73ac045

as you can see, v8 interpreter working on same stack frame.

  1. direct accessing previous RET
    v8 interpreter does not follow calling convention as mention at first case. sometime v8 interpreter access previous stack frame directly. this used for read function arguments at normal case. but v8 interpreter access previous stack frame directly for read RET. this is not allowed in calling convention. in this time, mcount_return_fn address will be exist in RET because uftrace hook the RET to mcount_return_fn in reset function. so, v8 will crashed on.

problem occurred at here:

Dump of assembler code for function Builtins_CEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit:
0x00007ffff772ee24 <+100>:   mov    rcx,QWORD PTR [rbp+0x8]                                                                                                                                                                                  0x00007ffff772ee28 <+104>:   mov    rbp,QWORD PTR [rbp+0x0]                                                                                                                                                                                  0x00007ffff772ee2c <+108>:   lea    rsp,[r15+0x8]                                                                                                                                                                                            0x00007ffff772ee30 <+112>:   push   rcx                                                                                                                                                                                                   => 0x00007ffff772ee31 <+113>:   mov    rsi,QWORD PTR [r13+0x2f78]  

value that keep in rcx register:

Thread 2.1 "d8" hit Breakpoint 5, 0x00007ffff772ee24 in Builtins_CEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit () from /home/m/git/v8/v8/out.gn/x64.debug/./libv8.so
$1 = 0x7fffffffcac8

so, rcx has 0x7fffffffcac8 + 0x8 = 0x7fffffffcad0.
let's see what value has stored in 0x7fffffffcad0.

(gdb) call mcount_iterate_mtdp()
WARN: [IDX] [OFFSET] [PARENT_LOC](CURRENT_VALUE) [PARENT_VALUE](STORED) [CHILD]
WARN: [0] [0] 0x7fffffffcc18(value:0x7ffff6b4b58c)       0x7ffff6b4b58c  0x7ffff73bccc5
WARN: [1] [13] 0x7fffffffcbb0(value:0x7ffff73bcd38)      0x7ffff73bcd38  0x7ffff73bcf65
WARN: [2] [5] 0x7fffffffcb88(value:0x7ffff73bcfbd)       0x7ffff73bcfbd  0x7ffff73c75c5
WARN: [3] [23] 0x7fffffffcad0(value:0x7ffff7bbf4a3)      0x7ffff78faa1c  0x7ffff772edc5

(gdb) x/i 0x7ffff772edc5
   0x7ffff772edc5 <Builtins_CEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit+5>: nop

(gdb) p/x mtd->rstack[3]
$2 = {parent_loc = 0x7fffffffcad0, parent_ip = 0x7ffff78faa1c, child_ip = 0x7ffff772edc5, flags = 0x40, start_time = 0x216c8623942d9, end_time = 0x0, tid = 0x0, dyn_idx = 0xefefefef, filter_time = 0x0, depth = 0x3,
  filter_depth = 0x3fd, nr_events = 0x0, event_idx = 0x400, pd = 0x0, pargs = 0x0}

(gdb) x/i 0x7ffff73c75c5
   0x7ffff73c75c5 <Builtins_InterpreterEntryTrampoline+5>:      nop

f

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant