Home | History | Annotate | Download | only in profiler
      1 // Copyright 2013 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 "src/profiler/tick-sample.h"
      6 
      7 #include "src/frames-inl.h"
      8 #include "src/vm-state-inl.h"
      9 
     10 
     11 namespace v8 {
     12 namespace internal {
     13 
     14 namespace {
     15 
     16 bool IsSamePage(byte* ptr1, byte* ptr2) {
     17   const uint32_t kPageSize = 4096;
     18   uintptr_t mask = ~static_cast<uintptr_t>(kPageSize - 1);
     19   return (reinterpret_cast<uintptr_t>(ptr1) & mask) ==
     20          (reinterpret_cast<uintptr_t>(ptr2) & mask);
     21 }
     22 
     23 // Check if the code at specified address could potentially be a
     24 // frame setup code.
     25 bool IsNoFrameRegion(Address address) {
     26   struct Pattern {
     27     int bytes_count;
     28     byte bytes[8];
     29     int offsets[4];
     30   };
     31   byte* pc = reinterpret_cast<byte*>(address);
     32   static Pattern patterns[] = {
     33 #if V8_HOST_ARCH_IA32
     34     // push %ebp
     35     // mov %esp,%ebp
     36     {3, {0x55, 0x89, 0xe5}, {0, 1, -1}},
     37     // pop %ebp
     38     // ret N
     39     {2, {0x5d, 0xc2}, {0, 1, -1}},
     40     // pop %ebp
     41     // ret
     42     {2, {0x5d, 0xc3}, {0, 1, -1}},
     43 #elif V8_HOST_ARCH_X64
     44     // pushq %rbp
     45     // movq %rsp,%rbp
     46     {4, {0x55, 0x48, 0x89, 0xe5}, {0, 1, -1}},
     47     // popq %rbp
     48     // ret N
     49     {2, {0x5d, 0xc2}, {0, 1, -1}},
     50     // popq %rbp
     51     // ret
     52     {2, {0x5d, 0xc3}, {0, 1, -1}},
     53 #endif
     54     {0, {}, {}}
     55   };
     56   for (Pattern* pattern = patterns; pattern->bytes_count; ++pattern) {
     57     for (int* offset_ptr = pattern->offsets; *offset_ptr != -1; ++offset_ptr) {
     58       int offset = *offset_ptr;
     59       if (!offset || IsSamePage(pc, pc - offset)) {
     60         MSAN_MEMORY_IS_INITIALIZED(pc - offset, pattern->bytes_count);
     61         if (!memcmp(pc - offset, pattern->bytes, pattern->bytes_count))
     62           return true;
     63       } else {
     64         // It is not safe to examine bytes on another page as it might not be
     65         // allocated thus causing a SEGFAULT.
     66         // Check the pattern part that's on the same page and
     67         // pessimistically assume it could be the entire pattern match.
     68         MSAN_MEMORY_IS_INITIALIZED(pc, pattern->bytes_count - offset);
     69         if (!memcmp(pc, pattern->bytes + offset, pattern->bytes_count - offset))
     70           return true;
     71       }
     72     }
     73   }
     74   return false;
     75 }
     76 
     77 }  // namespace
     78 
     79 //
     80 // StackTracer implementation
     81 //
     82 DISABLE_ASAN void TickSample::Init(Isolate* isolate,
     83                                    const v8::RegisterState& regs,
     84                                    RecordCEntryFrame record_c_entry_frame,
     85                                    bool update_stats) {
     86   timestamp = base::TimeTicks::HighResolutionNow();
     87   this->update_stats = update_stats;
     88 
     89   SampleInfo info;
     90   if (GetStackSample(isolate, regs, record_c_entry_frame,
     91                      reinterpret_cast<void**>(&stack[0]), kMaxFramesCount,
     92                      &info)) {
     93     state = info.vm_state;
     94     pc = static_cast<Address>(regs.pc);
     95     frames_count = static_cast<unsigned>(info.frames_count);
     96     has_external_callback = info.external_callback_entry != nullptr;
     97     if (has_external_callback) {
     98       external_callback_entry =
     99           static_cast<Address>(info.external_callback_entry);
    100     } else if (frames_count) {
    101       // sp register may point at an arbitrary place in memory, make
    102       // sure MSAN doesn't complain about it.
    103       MSAN_MEMORY_IS_INITIALIZED(regs.sp, sizeof(Address));
    104       // Sample potential return address value for frameless invocation of
    105       // stubs (we'll figure out later, if this value makes sense).
    106       tos = Memory::Address_at(reinterpret_cast<Address>(regs.sp));
    107     } else {
    108       tos = nullptr;
    109     }
    110   } else {
    111     // It is executing JS but failed to collect a stack trace.
    112     // Mark the sample as spoiled.
    113     timestamp = base::TimeTicks();
    114     pc = nullptr;
    115   }
    116 }
    117 
    118 bool TickSample::GetStackSample(Isolate* isolate, const v8::RegisterState& regs,
    119                                 RecordCEntryFrame record_c_entry_frame,
    120                                 void** frames, size_t frames_limit,
    121                                 v8::SampleInfo* sample_info) {
    122   sample_info->frames_count = 0;
    123   sample_info->vm_state = isolate->current_vm_state();
    124   sample_info->external_callback_entry = nullptr;
    125   if (sample_info->vm_state == GC) return true;
    126 
    127   Address js_entry_sp = isolate->js_entry_sp();
    128   if (js_entry_sp == 0) return true;  // Not executing JS now.
    129 
    130   if (regs.pc && IsNoFrameRegion(static_cast<Address>(regs.pc))) {
    131     // Can't collect stack.
    132     return false;
    133   }
    134 
    135   ExternalCallbackScope* scope = isolate->external_callback_scope();
    136   Address handler = Isolate::handler(isolate->thread_local_top());
    137   // If there is a handler on top of the external callback scope then
    138   // we have already entrered JavaScript again and the external callback
    139   // is not the top function.
    140   if (scope && scope->scope_address() < handler) {
    141     sample_info->external_callback_entry =
    142         *scope->callback_entrypoint_address();
    143   }
    144 
    145   SafeStackFrameIterator it(isolate, reinterpret_cast<Address>(regs.fp),
    146                             reinterpret_cast<Address>(regs.sp), js_entry_sp);
    147   size_t i = 0;
    148   if (record_c_entry_frame == kIncludeCEntryFrame && !it.done() &&
    149       it.top_frame_type() == StackFrame::EXIT) {
    150     frames[i++] = isolate->c_function();
    151   }
    152   while (!it.done() && i < frames_limit) {
    153     if (it.frame()->is_interpreted()) {
    154       // For interpreted frames use the bytecode array pointer as the pc.
    155       InterpretedFrame* frame = static_cast<InterpretedFrame*>(it.frame());
    156       // Since the sampler can interrupt execution at any point the
    157       // bytecode_array might be garbage, so don't dereference it.
    158       Address bytecode_array =
    159           reinterpret_cast<Address>(frame->GetBytecodeArray()) - kHeapObjectTag;
    160       frames[i++] = bytecode_array + BytecodeArray::kHeaderSize +
    161                     frame->GetBytecodeOffset();
    162     } else {
    163       frames[i++] = it.frame()->pc();
    164     }
    165     it.Advance();
    166   }
    167   sample_info->frames_count = i;
    168   return true;
    169 }
    170 
    171 #if defined(USE_SIMULATOR)
    172 bool SimulatorHelper::FillRegisters(Isolate* isolate,
    173                                     v8::RegisterState* state) {
    174   Simulator *simulator = isolate->thread_local_top()->simulator_;
    175   // Check if there is active simulator.
    176   if (simulator == NULL) return false;
    177 #if V8_TARGET_ARCH_ARM
    178   if (!simulator->has_bad_pc()) {
    179     state->pc = reinterpret_cast<Address>(simulator->get_pc());
    180   }
    181   state->sp = reinterpret_cast<Address>(simulator->get_register(Simulator::sp));
    182   state->fp = reinterpret_cast<Address>(simulator->get_register(
    183       Simulator::r11));
    184 #elif V8_TARGET_ARCH_ARM64
    185   state->pc = reinterpret_cast<Address>(simulator->pc());
    186   state->sp = reinterpret_cast<Address>(simulator->sp());
    187   state->fp = reinterpret_cast<Address>(simulator->fp());
    188 #elif V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64
    189   if (!simulator->has_bad_pc()) {
    190     state->pc = reinterpret_cast<Address>(simulator->get_pc());
    191   }
    192   state->sp = reinterpret_cast<Address>(simulator->get_register(Simulator::sp));
    193   state->fp = reinterpret_cast<Address>(simulator->get_register(Simulator::fp));
    194 #elif V8_TARGET_ARCH_PPC
    195   if (!simulator->has_bad_pc()) {
    196     state->pc = reinterpret_cast<Address>(simulator->get_pc());
    197   }
    198   state->sp = reinterpret_cast<Address>(simulator->get_register(Simulator::sp));
    199   state->fp = reinterpret_cast<Address>(simulator->get_register(Simulator::fp));
    200 #elif V8_TARGET_ARCH_S390
    201   if (!simulator->has_bad_pc()) {
    202     state->pc = reinterpret_cast<Address>(simulator->get_pc());
    203   }
    204   state->sp = reinterpret_cast<Address>(simulator->get_register(Simulator::sp));
    205   state->fp = reinterpret_cast<Address>(simulator->get_register(Simulator::fp));
    206 #endif
    207   if (state->sp == 0 || state->fp == 0) {
    208     // It possible that the simulator is interrupted while it is updating
    209     // the sp or fp register. ARM64 simulator does this in two steps:
    210     // first setting it to zero and then setting it to the new value.
    211     // Bailout if sp/fp doesn't contain the new value.
    212     //
    213     // FIXME: The above doesn't really solve the issue.
    214     // If a 64-bit target is executed on a 32-bit host even the final
    215     // write is non-atomic, so it might obtain a half of the result.
    216     // Moreover as long as the register set code uses memcpy (as of now),
    217     // it is not guaranteed to be atomic even when both host and target
    218     // are of same bitness.
    219     return false;
    220   }
    221   return true;
    222 }
    223 #endif  // USE_SIMULATOR
    224 
    225 }  // namespace internal
    226 }  // namespace v8
    227