LCOV - code coverage report
Current view: top level - src - unwinder.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 26 26 100.0 %
Date: 2019-04-17 Functions: 2 2 100.0 %

          Line data    Source code
       1             : // Copyright 2018 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "include/v8.h"
       6             : #include "src/frame-constants.h"
       7             : #include "src/globals.h"
       8             : 
       9             : namespace v8 {
      10             : 
      11             : namespace {
      12             : 
      13             : bool PCIsInCodeRange(const v8::MemoryRange& code_range, void* pc) {
      14             :   // Given that the length of the memory range is in bytes and it is not
      15             :   // necessarily aligned, we need to do the pointer arithmetic in byte* here.
      16             :   const i::byte* pc_as_byte = reinterpret_cast<i::byte*>(pc);
      17         361 :   const i::byte* start = reinterpret_cast<const i::byte*>(code_range.start);
      18         361 :   const i::byte* end = start + code_range.length_in_bytes;
      19         361 :   return pc_as_byte >= start && pc_as_byte < end;
      20             : }
      21             : 
      22             : bool IsInUnsafeJSEntryRange(const v8::JSEntryStub& js_entry_stub, void* pc) {
      23             :   return PCIsInCodeRange(js_entry_stub.code, pc);
      24             : 
      25             :   // TODO(petermarshall): We can be more precise by checking whether we are
      26             :   // in JSEntry but after frame setup and before frame teardown, in which case
      27             :   // we are safe to unwind the stack. For now, we bail out if the PC is anywhere
      28             :   // within JSEntry.
      29             : }
      30             : 
      31             : i::Address Load(i::Address address) {
      32         108 :   return *reinterpret_cast<i::Address*>(address);
      33             : }
      34             : 
      35             : void* GetReturnAddressFromFP(void* fp) {
      36             :   return reinterpret_cast<void*>(
      37          54 :       Load(reinterpret_cast<i::Address>(fp) +
      38          54 :            i::CommonFrameConstants::kCallerPCOffset));
      39             : }
      40             : 
      41             : void* GetCallerFPFromFP(void* fp) {
      42             :   return reinterpret_cast<void*>(
      43             :       Load(reinterpret_cast<i::Address>(fp) +
      44          54 :            i::CommonFrameConstants::kCallerFPOffset));
      45             : }
      46             : 
      47             : void* GetCallerSPFromFP(void* fp) {
      48          34 :   return reinterpret_cast<void*>(reinterpret_cast<i::Address>(fp) +
      49          34 :                                  i::CommonFrameConstants::kCallerSPOffset);
      50             : }
      51             : 
      52             : bool AddressIsInStack(const void* address, const void* stack_base,
      53             :                       const void* stack_top) {
      54          98 :   return address <= stack_base && address >= stack_top;
      55             : }
      56             : 
      57             : }  // namespace
      58             : 
      59          64 : bool Unwinder::TryUnwindV8Frames(const UnwindState& unwind_state,
      60             :                                  RegisterState* register_state,
      61             :                                  const void* stack_base) {
      62          64 :   const void* stack_top = register_state->sp;
      63             : 
      64          64 :   void* pc = register_state->pc;
      65         123 :   if (PCIsInV8(unwind_state, pc) &&
      66             :       !IsInUnsafeJSEntryRange(unwind_state.js_entry_stub, pc)) {
      67          44 :     void* current_fp = register_state->fp;
      68          44 :     if (!AddressIsInStack(current_fp, stack_base, stack_top)) return false;
      69             : 
      70             :     // Peek at the return address that the caller pushed. If it's in V8, then we
      71             :     // assume the caller frame is a JS frame and continue to unwind.
      72             :     void* next_pc = GetReturnAddressFromFP(current_fp);
      73          69 :     while (PCIsInV8(unwind_state, next_pc)) {
      74             :       current_fp = GetCallerFPFromFP(current_fp);
      75          20 :       if (!AddressIsInStack(current_fp, stack_base, stack_top)) return false;
      76             :       next_pc = GetReturnAddressFromFP(current_fp);
      77             :     }
      78             : 
      79             :     void* final_sp = GetCallerSPFromFP(current_fp);
      80          34 :     if (!AddressIsInStack(final_sp, stack_base, stack_top)) return false;
      81          34 :     register_state->sp = final_sp;
      82             : 
      83             :     // We don't check that the final FP value is within the stack bounds because
      84             :     // this is just the rbp value that JSEntryStub pushed. On platforms like
      85             :     // Win64 this is not used as a dedicated FP register, and could contain
      86             :     // anything.
      87             :     void* final_fp = GetCallerFPFromFP(current_fp);
      88          34 :     register_state->fp = final_fp;
      89             : 
      90          34 :     register_state->pc = next_pc;
      91          34 :     return true;
      92             :   }
      93             :   return false;
      94             : }
      95             : 
      96          90 : bool Unwinder::PCIsInV8(const UnwindState& unwind_state, void* pc) {
      97         510 :   return pc && (PCIsInCodeRange(unwind_state.code_range, pc) ||
      98          90 :                 PCIsInCodeRange(unwind_state.embedded_code_range, pc));
      99             : }
     100             : 
     101             : }  // namespace v8

Generated by: LCOV version 1.10