| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "platform/address_sanitizer.h" | 5 #include "platform/address_sanitizer.h" |
| 6 #include "platform/memory_sanitizer.h" | 6 #include "platform/memory_sanitizer.h" |
| 7 #include "platform/utils.h" | 7 #include "platform/utils.h" |
| 8 | 8 |
| 9 #include "vm/allocation.h" | 9 #include "vm/allocation.h" |
| 10 #include "vm/atomic.h" | 10 #include "vm/atomic.h" |
| (...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 270 cursor = cursor % capacity_; | 270 cursor = cursor % capacity_; |
| 271 return At(cursor); | 271 return At(cursor); |
| 272 } | 272 } |
| 273 | 273 |
| 274 // Attempts to find the true return address when a Dart frame is being setup | 274 // Attempts to find the true return address when a Dart frame is being setup |
| 275 // or torn down. | 275 // or torn down. |
| 276 // NOTE: Architecture specific implementations below. | 276 // NOTE: Architecture specific implementations below. |
| 277 class ReturnAddressLocator : public ValueObject { | 277 class ReturnAddressLocator : public ValueObject { |
| 278 public: | 278 public: |
| 279 ReturnAddressLocator(Sample* sample, const Code& code) | 279 ReturnAddressLocator(Sample* sample, const Code& code) |
| 280 : sample_(sample), | 280 : stack_buffer_(sample->GetStackBuffer()), |
| 281 pc_(sample->pc()), |
| 281 code_(Code::ZoneHandle(code.raw())) { | 282 code_(Code::ZoneHandle(code.raw())) { |
| 282 ASSERT(!code_.IsNull()); | 283 ASSERT(!code_.IsNull()); |
| 283 ASSERT(code_.ContainsInstructionAt(pc())); | 284 ASSERT(code_.ContainsInstructionAt(pc())); |
| 284 } | 285 } |
| 285 | 286 |
| 287 ReturnAddressLocator(uword pc, uword* stack_buffer, const Code& code) |
| 288 : stack_buffer_(stack_buffer), |
| 289 pc_(pc), |
| 290 code_(Code::ZoneHandle(code.raw())) { |
| 291 ASSERT(!code_.IsNull()); |
| 292 ASSERT(code_.ContainsInstructionAt(pc_)); |
| 293 } |
| 294 |
| 286 uword pc() { | 295 uword pc() { |
| 287 return sample_->pc(); | 296 return pc_; |
| 288 } | 297 } |
| 289 | 298 |
| 290 // Returns false on failure. | 299 // Returns false on failure. |
| 291 bool LocateReturnAddress(uword* return_address); | 300 bool LocateReturnAddress(uword* return_address); |
| 292 | 301 |
| 293 // Returns offset into code object. | 302 // Returns offset into code object. |
| 294 intptr_t RelativePC() { | 303 intptr_t RelativePC() { |
| 295 ASSERT(pc() >= code_.EntryPoint()); | 304 ASSERT(pc() >= code_.EntryPoint()); |
| 296 return static_cast<intptr_t>(pc() - code_.EntryPoint()); | 305 return static_cast<intptr_t>(pc() - code_.EntryPoint()); |
| 297 } | 306 } |
| 298 | 307 |
| 299 uint8_t* CodePointer(intptr_t offset) { | 308 uint8_t* CodePointer(intptr_t offset) { |
| 300 const intptr_t size = code_.Size(); | 309 const intptr_t size = code_.Size(); |
| 301 ASSERT(offset < size); | 310 ASSERT(offset < size); |
| 302 uint8_t* code_pointer = reinterpret_cast<uint8_t*>(code_.EntryPoint()); | 311 uint8_t* code_pointer = reinterpret_cast<uint8_t*>(code_.EntryPoint()); |
| 303 code_pointer += offset; | 312 code_pointer += offset; |
| 304 return code_pointer; | 313 return code_pointer; |
| 305 } | 314 } |
| 306 | 315 |
| 307 uword StackAt(intptr_t i) { | 316 uword StackAt(intptr_t i) { |
| 308 ASSERT(i >= 0); | 317 ASSERT(i >= 0); |
| 309 ASSERT(i < Sample::kStackBufferSizeInWords); | 318 ASSERT(i < Sample::kStackBufferSizeInWords); |
| 310 return sample_->GetStackBuffer()[i]; | 319 return stack_buffer_[i]; |
| 311 } | 320 } |
| 312 | 321 |
| 313 private: | 322 private: |
| 314 Sample* sample_; | 323 uword* stack_buffer_; |
| 324 uword pc_; |
| 315 const Code& code_; | 325 const Code& code_; |
| 316 }; | 326 }; |
| 317 | 327 |
| 318 | 328 |
| 319 #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64) | 329 #if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64) |
| 320 bool ReturnAddressLocator::LocateReturnAddress(uword* return_address) { | 330 bool ReturnAddressLocator::LocateReturnAddress(uword* return_address) { |
| 321 ASSERT(return_address != NULL); | 331 ASSERT(return_address != NULL); |
| 322 const intptr_t offset = RelativePC(); | 332 const intptr_t offset = RelativePC(); |
| 323 ASSERT(offset >= 0); | 333 ASSERT(offset >= 0); |
| 324 const intptr_t size = code_.Size(); | 334 const intptr_t size = code_.Size(); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 378 #elif defined(TARGET_ARCH_MIPS) | 388 #elif defined(TARGET_ARCH_MIPS) |
| 379 bool ReturnAddressLocator::LocateReturnAddress(uword* return_address) { | 389 bool ReturnAddressLocator::LocateReturnAddress(uword* return_address) { |
| 380 ASSERT(return_address != NULL); | 390 ASSERT(return_address != NULL); |
| 381 return false; | 391 return false; |
| 382 } | 392 } |
| 383 #else | 393 #else |
| 384 #error ReturnAddressLocator implementation missing for this architecture. | 394 #error ReturnAddressLocator implementation missing for this architecture. |
| 385 #endif | 395 #endif |
| 386 | 396 |
| 387 | 397 |
| 388 PreprocessVisitor::PreprocessVisitor(Isolate* isolate) | |
| 389 : SampleVisitor(isolate), | |
| 390 vm_isolate_(Dart::vm_isolate()) { | |
| 391 } | |
| 392 | |
| 393 | |
| 394 void PreprocessVisitor::VisitSample(Sample* sample) { | |
| 395 if (sample->processed()) { | |
| 396 // Already processed. | |
| 397 return; | |
| 398 } | |
| 399 // Mark that we've processed this sample. | |
| 400 sample->set_processed(true); | |
| 401 | |
| 402 if (sample->exit_frame_sample()) { | |
| 403 // Exit frame sample, no preprocessing required. | |
| 404 return; | |
| 405 } | |
| 406 REUSABLE_CODE_HANDLESCOPE(isolate()); | |
| 407 // Lookup code object for leaf frame. | |
| 408 Code& code = reused_code_handle.Handle(); | |
| 409 code = FindCodeForPC(sample->At(0)); | |
| 410 sample->set_leaf_frame_is_dart(!code.IsNull()); | |
| 411 if (!code.IsNull() && (code.compile_timestamp() > sample->timestamp())) { | |
| 412 // Code compiled after sample. Ignore. | |
| 413 return; | |
| 414 } | |
| 415 if (sample->leaf_frame_is_dart()) { | |
| 416 CheckForMissingDartFrame(code, sample); | |
| 417 } | |
| 418 } | |
| 419 | |
| 420 | |
| 421 void PreprocessVisitor::CheckForMissingDartFrame(const Code& code, | |
| 422 Sample* sample) const { | |
| 423 // Some stubs (and intrinsics) do not push a frame onto the stack leaving | |
| 424 // the frame pointer in the caller. | |
| 425 // | |
| 426 // PC -> STUB | |
| 427 // FP -> DART3 <-+ | |
| 428 // DART2 <-| <- TOP FRAME RETURN ADDRESS. | |
| 429 // DART1 <-| | |
| 430 // ..... | |
| 431 // | |
| 432 // In this case, traversing the linked stack frames will not collect a PC | |
| 433 // inside DART3. The stack will incorrectly be: STUB, DART2, DART1. | |
| 434 // In Dart code, after pushing the FP onto the stack, an IP in the current | |
| 435 // function is pushed onto the stack as well. This stack slot is called | |
| 436 // the PC marker. We can use the PC marker to insert DART3 into the stack | |
| 437 // so that it will correctly be: STUB, DART3, DART2, DART1. Note the | |
| 438 // inserted PC may not accurately reflect the true return address into DART3. | |
| 439 ASSERT(!code.IsNull()); | |
| 440 | |
| 441 // The pc marker is our current best guess of a return address. | |
| 442 uword return_address = sample->pc_marker(); | |
| 443 | |
| 444 // Attempt to find a better return address. | |
| 445 ReturnAddressLocator ral(sample, code); | |
| 446 | |
| 447 if (!ral.LocateReturnAddress(&return_address)) { | |
| 448 ASSERT(return_address == sample->pc_marker()); | |
| 449 if (code.GetPrologueOffset() == 0) { | |
| 450 // Code has the prologue at offset 0. The frame is already setup and | |
| 451 // can be trusted. | |
| 452 return; | |
| 453 } | |
| 454 // Could not find a better return address than the pc_marker. | |
| 455 if (code.ContainsInstructionAt(return_address)) { | |
| 456 // PC marker is in the same code as pc, no missing frame. | |
| 457 return; | |
| 458 } | |
| 459 } | |
| 460 | |
| 461 if (!ContainedInDartCodeHeaps(return_address)) { | |
| 462 // return address is not from the Dart heap. Do not insert. | |
| 463 return; | |
| 464 } | |
| 465 | |
| 466 if (return_address != 0) { | |
| 467 sample->InsertCallerForTopFrame(return_address); | |
| 468 } | |
| 469 } | |
| 470 | |
| 471 | |
| 472 bool PreprocessVisitor::ContainedInDartCodeHeaps(uword pc) const { | |
| 473 return isolate()->heap()->CodeContains(pc) || | |
| 474 vm_isolate()->heap()->CodeContains(pc); | |
| 475 } | |
| 476 | |
| 477 | |
| 478 RawCode* PreprocessVisitor::FindCodeForPC(uword pc) const { | |
| 479 // Check current isolate for pc. | |
| 480 if (isolate()->heap()->CodeContains(pc)) { | |
| 481 return Code::LookupCode(pc); | |
| 482 } | |
| 483 // Check VM isolate for pc. | |
| 484 if (vm_isolate()->heap()->CodeContains(pc)) { | |
| 485 return Code::LookupCodeInVmIsolate(pc); | |
| 486 } | |
| 487 return Code::null(); | |
| 488 } | |
| 489 | |
| 490 | |
| 491 ClearProfileVisitor::ClearProfileVisitor(Isolate* isolate) | 398 ClearProfileVisitor::ClearProfileVisitor(Isolate* isolate) |
| 492 : SampleVisitor(isolate) { | 399 : SampleVisitor(isolate) { |
| 493 } | 400 } |
| 494 | 401 |
| 495 | 402 |
| 496 void ClearProfileVisitor::VisitSample(Sample* sample) { | 403 void ClearProfileVisitor::VisitSample(Sample* sample) { |
| 497 sample->Clear(); | 404 sample->Clear(); |
| 498 } | 405 } |
| 499 | 406 |
| 500 | 407 |
| (...skipping 572 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1073 in_dart_code, | 980 in_dart_code, |
| 1074 sample, | 981 sample, |
| 1075 &native_stack_walker, | 982 &native_stack_walker, |
| 1076 &dart_exit_stack_walker, | 983 &dart_exit_stack_walker, |
| 1077 &dart_stack_walker, | 984 &dart_stack_walker, |
| 1078 pc, | 985 pc, |
| 1079 fp, | 986 fp, |
| 1080 sp); | 987 sp); |
| 1081 } | 988 } |
| 1082 | 989 |
| 990 |
| 991 ProcessedSampleBuffer* SampleBuffer::BuildProcessedSampleBuffer( |
| 992 SampleFilter* filter) { |
| 993 ASSERT(filter != NULL); |
| 994 Thread* thread = Thread::Current(); |
| 995 Zone* zone = thread->zone(); |
| 996 |
| 997 ProcessedSampleBuffer* buffer = new(zone) ProcessedSampleBuffer(); |
| 998 |
| 999 const intptr_t length = capacity(); |
| 1000 for (intptr_t i = 0; i < length; i++) { |
| 1001 Sample* sample = At(i); |
| 1002 if (sample->ignore_sample()) { |
| 1003 // Bad sample. |
| 1004 continue; |
| 1005 } |
| 1006 if (sample->isolate() != filter->isolate()) { |
| 1007 // Another isolate. |
| 1008 continue; |
| 1009 } |
| 1010 if (sample->timestamp() == 0) { |
| 1011 // Empty. |
| 1012 continue; |
| 1013 } |
| 1014 if (sample->At(0) == 0) { |
| 1015 // No frames. |
| 1016 continue; |
| 1017 } |
| 1018 if (!filter->FilterSample(sample)) { |
| 1019 // Did not pass filter. |
| 1020 continue; |
| 1021 } |
| 1022 buffer->Add(BuildProcessedSample(sample)); |
| 1023 } |
| 1024 return buffer; |
| 1025 } |
| 1026 |
| 1027 |
| 1028 ProcessedSample* SampleBuffer::BuildProcessedSample(Sample* sample) { |
| 1029 Thread* thread = Thread::Current(); |
| 1030 Zone* zone = thread->zone(); |
| 1031 |
| 1032 ProcessedSample* processed_sample = new(zone) ProcessedSample(); |
| 1033 |
| 1034 // Copy state bits from sample. |
| 1035 processed_sample->set_timestamp(sample->timestamp()); |
| 1036 processed_sample->set_vm_tag(sample->vm_tag()); |
| 1037 processed_sample->set_user_tag(sample->user_tag()); |
| 1038 if (sample->is_allocation_sample()) { |
| 1039 processed_sample->set_cid(sample->allocation_cid()); |
| 1040 } |
| 1041 processed_sample->set_first_frame_executing(!sample->exit_frame_sample()); |
| 1042 |
| 1043 // Copy stack trace from sample(s). |
| 1044 bool truncated = false; |
| 1045 Sample* current = sample; |
| 1046 while (current != NULL) { |
| 1047 for (intptr_t i = 0; i < FLAG_profile_depth; i++) { |
| 1048 if (current->At(i) == 0) { |
| 1049 break; |
| 1050 } |
| 1051 processed_sample->Add(current->At(i)); |
| 1052 } |
| 1053 |
| 1054 truncated = truncated || current->truncated_trace(); |
| 1055 current = Next(sample); |
| 1056 } |
| 1057 |
| 1058 if (!sample->exit_frame_sample()) { |
| 1059 Isolate* isolate = thread->isolate(); |
| 1060 Isolate* vm_isolate = Dart::vm_isolate(); |
| 1061 processed_sample->FixupCaller(isolate, |
| 1062 vm_isolate, |
| 1063 sample->pc_marker(), |
| 1064 sample->GetStackBuffer()); |
| 1065 } |
| 1066 |
| 1067 processed_sample->set_truncated(truncated); |
| 1068 return processed_sample; |
| 1069 } |
| 1070 |
| 1071 |
| 1072 Sample* SampleBuffer::Next(Sample* sample) { |
| 1073 // TODO(johnmccutchan): Support chaining samples for complete stack traces. |
| 1074 return NULL; |
| 1075 } |
| 1076 |
| 1077 |
| 1078 ProcessedSample::ProcessedSample() |
| 1079 : pcs_(FLAG_profile_depth), |
| 1080 timestamp_(0), |
| 1081 vm_tag_(0), |
| 1082 user_tag_(0), |
| 1083 cid_(-1), |
| 1084 truncated_(false) { |
| 1085 } |
| 1086 |
| 1087 |
| 1088 void ProcessedSample::FixupCaller(Isolate* isolate, |
| 1089 Isolate* vm_isolate, |
| 1090 uword pc_marker, |
| 1091 uword* stack_buffer) { |
| 1092 REUSABLE_CODE_HANDLESCOPE(isolate); |
| 1093 // Lookup code object for leaf frame. |
| 1094 Code& code = reused_code_handle.Handle(); |
| 1095 code = FindCodeForPC(isolate, vm_isolate, At(0)); |
| 1096 if (code.IsNull()) { |
| 1097 return; |
| 1098 } |
| 1099 if (code.compile_timestamp() > timestamp()) { |
| 1100 // Code compiled after sample. Ignore. |
| 1101 return; |
| 1102 } |
| 1103 CheckForMissingDartFrame(isolate, vm_isolate, code, pc_marker, stack_buffer); |
| 1104 } |
| 1105 |
| 1106 |
| 1107 void ProcessedSample::CheckForMissingDartFrame(Isolate* isolate, |
| 1108 Isolate* vm_isolate, |
| 1109 const Code& code, |
| 1110 uword pc_marker, |
| 1111 uword* stack_buffer) { |
| 1112 // Some stubs (and intrinsics) do not push a frame onto the stack leaving |
| 1113 // the frame pointer in the caller. |
| 1114 // |
| 1115 // PC -> STUB |
| 1116 // FP -> DART3 <-+ |
| 1117 // DART2 <-| <- TOP FRAME RETURN ADDRESS. |
| 1118 // DART1 <-| |
| 1119 // ..... |
| 1120 // |
| 1121 // In this case, traversing the linked stack frames will not collect a PC |
| 1122 // inside DART3. The stack will incorrectly be: STUB, DART2, DART1. |
| 1123 // In Dart code, after pushing the FP onto the stack, an IP in the current |
| 1124 // function is pushed onto the stack as well. This stack slot is called |
| 1125 // the PC marker. We can use the PC marker to insert DART3 into the stack |
| 1126 // so that it will correctly be: STUB, DART3, DART2, DART1. Note the |
| 1127 // inserted PC may not accurately reflect the true return address into DART3. |
| 1128 ASSERT(!code.IsNull()); |
| 1129 |
| 1130 // The pc marker is our current best guess of a return address. |
| 1131 uword return_address = pc_marker; |
| 1132 |
| 1133 // Attempt to find a better return address. |
| 1134 ReturnAddressLocator ral(At(0), stack_buffer, code); |
| 1135 |
| 1136 if (!ral.LocateReturnAddress(&return_address)) { |
| 1137 ASSERT(return_address == pc_marker); |
| 1138 if (code.GetPrologueOffset() == 0) { |
| 1139 // Code has the prologue at offset 0. The frame is already setup and |
| 1140 // can be trusted. |
| 1141 return; |
| 1142 } |
| 1143 // Could not find a better return address than the pc_marker. |
| 1144 if (code.ContainsInstructionAt(return_address)) { |
| 1145 // PC marker is in the same code as pc, no missing frame. |
| 1146 return; |
| 1147 } |
| 1148 } |
| 1149 |
| 1150 if (!ContainedInDartCodeHeaps(isolate, vm_isolate, return_address)) { |
| 1151 // return address is not from the Dart heap. Do not insert. |
| 1152 return; |
| 1153 } |
| 1154 |
| 1155 if (return_address != 0) { |
| 1156 InsertAt(1, return_address); |
| 1157 } |
| 1158 } |
| 1159 |
| 1160 |
| 1161 RawCode* ProcessedSample::FindCodeForPC(Isolate* isolate, |
| 1162 Isolate* vm_isolate, |
| 1163 uword pc) { |
| 1164 // Check current isolate for pc. |
| 1165 if (isolate->heap()->CodeContains(pc)) { |
| 1166 return Code::LookupCode(pc); |
| 1167 } |
| 1168 |
| 1169 // Check VM isolate for pc. |
| 1170 if (vm_isolate->heap()->CodeContains(pc)) { |
| 1171 return Code::LookupCodeInVmIsolate(pc); |
| 1172 } |
| 1173 |
| 1174 return Code::null(); |
| 1175 } |
| 1176 |
| 1177 |
| 1178 bool ProcessedSample::ContainedInDartCodeHeaps(Isolate* isolate, |
| 1179 Isolate* vm_isolate, |
| 1180 uword pc) { |
| 1181 return vm_isolate->heap()->CodeContains(pc) |
| 1182 || isolate->heap()->CodeContains(pc); |
| 1183 } |
| 1184 |
| 1185 |
| 1186 ProcessedSampleBuffer::ProcessedSampleBuffer() { |
| 1187 } |
| 1188 |
| 1083 } // namespace dart | 1189 } // namespace dart |
| OLD | NEW |