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