Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(124)

Side by Side Diff: runtime/vm/profiler_service.cc

Issue 2939853002: [fuchsia] Make profile processing resilient to bogus overlaps from dladdr. (Closed)
Patch Set: verify too slow to leave on Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « runtime/vm/profiler_service.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, 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 "vm/profiler_service.h" 5 #include "vm/profiler_service.h"
6 6
7 #include "vm/growable_array.h" 7 #include "vm/growable_array.h"
8 #include "vm/hash_map.h" 8 #include "vm/hash_map.h"
9 #include "vm/log.h" 9 #include "vm/log.h"
10 #include "vm/malloc_hooks.h" 10 #include "vm/malloc_hooks.h"
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after
295 inclusive_ticks_(0), 295 inclusive_ticks_(0),
296 inclusive_serial_(-1), 296 inclusive_serial_(-1),
297 code_(code), 297 code_(code),
298 name_(NULL), 298 name_(NULL),
299 compile_timestamp_(0), 299 compile_timestamp_(0),
300 function_(NULL), 300 function_(NULL),
301 code_table_index_(-1), 301 code_table_index_(-1),
302 address_ticks_(0) {} 302 address_ticks_(0) {}
303 303
304 304
305 void ProfileCode::AdjustExtent(uword start, uword end) { 305 void ProfileCode::TruncateLower(uword start) {
306 if (start > start_) {
307 start_ = start;
308 }
309 ASSERT(start_ < end_);
310 }
311
312
313 void ProfileCode::TruncateUpper(uword end) {
314 if (end < end_) {
315 end_ = end;
316 }
317 ASSERT(start_ < end_);
318 }
319
320
321 void ProfileCode::ExpandLower(uword start) {
306 if (start < start_) { 322 if (start < start_) {
307 start_ = start; 323 start_ = start;
308 } 324 }
325 ASSERT(start_ < end_);
326 }
327
328
329 void ProfileCode::ExpandUpper(uword end) {
309 if (end > end_) { 330 if (end > end_) {
310 end_ = end; 331 end_ = end;
311 } 332 }
312 ASSERT(start_ < end_); 333 ASSERT(start_ < end_);
313 } 334 }
314 335
315 336
316 bool ProfileCode::Overlaps(const ProfileCode* other) const { 337 bool ProfileCode::Overlaps(const ProfileCode* other) const {
317 ASSERT(other != NULL); 338 ASSERT(other != NULL);
318 return other->Contains(start_) || other->Contains(end_ - 1) || 339 return other->Contains(start_) || other->Contains(end_ - 1) ||
(...skipping 371 matching lines...) Expand 10 before | Expand all | Expand 10 after
690 711
691 function->AddProfileCode(code_table_index()); 712 function->AddProfileCode(code_table_index());
692 713
693 function_ = function; 714 function_ = function;
694 return function_; 715 return function_;
695 } 716 }
696 717
697 718
698 typedef bool (*RangeCompare)(uword pc, uword region_start, uword region_end); 719 typedef bool (*RangeCompare)(uword pc, uword region_start, uword region_end);
699 720
700 class ProfileCodeTable : public ZoneAllocated { 721 class ProfileCodeTable : public ZoneAllocated {
zra 2017/06/14 05:00:05 Could you add unit tests for this class? If you mo
rmacnak 2017/06/14 17:32:14 Done. Adjusted neighbor test to compare end instea
701 public: 722 public:
702 ProfileCodeTable() : table_(8) {} 723 ProfileCodeTable() : table_(8) {}
703 724
704 intptr_t length() const { return table_.length(); } 725 intptr_t length() const { return table_.length(); }
705 726
706 ProfileCode* At(intptr_t index) const { 727 ProfileCode* At(intptr_t index) const {
707 ASSERT(index >= 0); 728 ASSERT(index >= 0);
708 ASSERT(index < length()); 729 ASSERT(index < length());
709 return table_[index]; 730 return table_[index];
710 } 731 }
711 732
712 // Find the table index to the ProfileCode containing pc. 733 // Find the table index to the ProfileCode containing pc.
713 // Returns < 0 if not found. 734 // Returns < 0 if not found.
714 intptr_t FindCodeIndexForPC(uword pc) const { 735 intptr_t FindCodeIndexForPC(uword pc) const {
715 intptr_t index = FindCodeIndex(pc, &CompareLowerBound); 736 intptr_t length = table_.length();
716 if (index == length()) { 737 if (length == 0) {
717 // Not present. 738 return -1; // No found.
zra 2017/06/14 05:00:05 Not
rmacnak 2017/06/14 17:32:14 Done.
718 return -1;
719 } 739 }
720 const ProfileCode* code = At(index); 740 intptr_t lo = 0;
721 if (!code->Contains(pc)) { 741 intptr_t hi = length - 1;
722 // Not present. 742 while (lo <= hi) {
723 return -1; 743 intptr_t mid = (hi - lo + 1) / 2 + lo;
744 ASSERT(mid >= lo);
745 ASSERT(mid <= hi);
746 ProfileCode* code = At(mid);
747 if (code->Contains(pc)) {
748 return mid;
749 } else if (pc < code->start()) {
750 hi = mid - 1;
751 } else {
752 lo = mid + 1;
753 }
724 } 754 }
725 // Found at index. 755 return -1;
726 return index;
727 } 756 }
728 757
729 ProfileCode* FindCodeForPC(uword pc) const { 758 ProfileCode* FindCodeForPC(uword pc) const {
730 intptr_t index = FindCodeIndexForPC(pc); 759 intptr_t index = FindCodeIndexForPC(pc);
731 if (index < 0) { 760 if (index < 0) {
732 return NULL; 761 return NULL;
733 } 762 }
734 return At(index); 763 return At(index);
735 } 764 }
736 765
737 // Insert |new_code| into the table. Returns the table index where |new_code| 766 // Insert |new_code| into the table. Returns the table index where |new_code|
738 // was inserted. Will merge with an overlapping ProfileCode if one is present. 767 // was inserted. Will merge with an overlapping ProfileCode if one is present.
739 intptr_t InsertCode(ProfileCode* new_code) { 768 intptr_t InsertCode(ProfileCode* new_code) {
740 const uword start = new_code->start();
741 const uword end = new_code->end();
742 const intptr_t length = table_.length(); 769 const intptr_t length = table_.length();
743 if (length == 0) { 770 if (length == 0) {
744 table_.Add(new_code); 771 table_.Add(new_code);
745 return length; 772 return length;
746 } 773 }
774
747 // Determine the correct place to insert or merge |new_code| into table. 775 // Determine the correct place to insert or merge |new_code| into table.
748 intptr_t lo = FindCodeIndex(start, &CompareLowerBound); 776 intptr_t lo = -1;
749 intptr_t hi = FindCodeIndex(end - 1, &CompareUpperBound); 777 intptr_t hi = -1;
750 // TODO(johnmccutchan): Simplify below logic. 778 ProfileCode* lo_code = NULL;
751 if ((lo == length) && (hi == length)) { 779 ProfileCode* hi_code = NULL;
752 lo = length - 1; 780 const uword pc = new_code->end() - 1;
781 FindNeighbors(pc, &lo, &hi, &lo_code, &hi_code);
782 ASSERT((lo_code != NULL) || (hi_code != NULL));
783
784 if (lo != -1) {
785 // Has left neighbor.
786 new_code->TruncateLower(lo_code->end());
787 ASSERT(!new_code->Overlaps(lo_code));
753 } 788 }
754 if (lo == length) { 789 if (hi != -1) {
755 ProfileCode* code = At(hi); 790 // Has right neighbor.
756 if (code->Overlaps(new_code)) { 791 new_code->TruncateUpper(hi_code->start());
757 HandleOverlap(code, new_code, start, end); 792 ASSERT(!new_code->Overlaps(hi_code));
758 return hi; 793 }
759 } 794
760 table_.Add(new_code); 795 if ((lo != -1) && (lo_code->kind() == ProfileCode::kNativeCode) &&
761 return length; 796 (new_code->kind() == ProfileCode::kNativeCode) &&
762 } else if (hi == length) { 797 (lo_code->end() == new_code->start())) {
763 ProfileCode* code = At(lo); 798 // Adjacent left neighbor of the same kind: merge.
764 if (code->Overlaps(new_code)) { 799 // (dladdr doesn't give us symbol size so we may new PCs we didn't
zra 2017/06/14 05:00:05 may see new PCs
rmacnak 2017/06/14 17:32:14 Done.
765 HandleOverlap(code, new_code, start, end); 800 // previously know belonged to it.)
766 return lo; 801 lo_code->ExpandUpper(new_code->end());
767 }
768 table_.Add(new_code);
769 return length;
770 } else if (lo == hi) {
771 ProfileCode* code = At(lo);
772 if (code->Overlaps(new_code)) {
773 HandleOverlap(code, new_code, start, end);
774 return lo;
775 }
776 table_.InsertAt(lo, new_code);
777 return lo; 802 return lo;
778 } else { 803 }
779 ProfileCode* code = At(lo); 804
780 if (code->Overlaps(new_code)) { 805 if ((hi != -1) && (hi_code->kind() == ProfileCode::kNativeCode) &&
781 HandleOverlap(code, new_code, start, end); 806 (new_code->kind() == ProfileCode::kNativeCode) &&
782 return lo; 807 (new_code->end() == hi_code->start())) {
783 } 808 // Adjacent right neighbor of the same kind: merge.
784 code = At(hi); 809 // (dladdr doesn't give us symbol size so we may new PCs we didn't
zra 2017/06/14 05:00:05 may see new PCs
rmacnak 2017/06/14 17:32:14 Done.
785 if (code->Overlaps(new_code)) { 810 // previously know belonged to it.)
786 HandleOverlap(code, new_code, start, end); 811 hi_code->ExpandLower(new_code->start());
787 return hi;
788 }
789 table_.InsertAt(hi, new_code);
790 return hi; 812 return hi;
791 } 813 }
792 UNREACHABLE(); 814
793 return -1; 815 intptr_t insert;
816 if (lo == -1) {
817 insert = 0;
818 } else if (hi == -1) {
819 insert = length;
820 } else {
821 insert = lo + 1;
822 }
823 table_.InsertAt(insert, new_code);
824 return insert;
794 } 825 }
795 826
796 private: 827 private:
797 intptr_t FindCodeIndex(uword pc, RangeCompare comparator) const { 828 void FindNeighbors(uword pc,
798 ASSERT(comparator != NULL); 829 intptr_t* lo,
799 intptr_t count = table_.length(); 830 intptr_t* hi,
800 intptr_t first = 0; 831 ProfileCode** lo_code,
801 while (count > 0) { 832 ProfileCode** hi_code) const {
802 intptr_t it = first; 833 ASSERT(table_.length() >= 1);
803 intptr_t step = count / 2; 834
804 it += step; 835 intptr_t length = table_.length();
805 const ProfileCode* code = At(it); 836
806 if (comparator(pc, code->start(), code->end())) { 837 if (pc < At(0)->start()) {
807 first = ++it; 838 // Lower than any existing code.
808 count -= (step + 1); 839 *lo = -1;
809 } else { 840 *lo_code = NULL;
810 count = step; 841 *hi = 0;
842 *hi_code = At(*hi);
843 return;
844 }
845
846 if (pc >= At(length - 1)->end()) {
847 // Higher than any existing code.
848 *lo = length - 1;
849 *lo_code = At(*lo);
850 *hi = -1;
851 *hi_code = NULL;
852 return;
853 }
854
855 *lo = 0;
856 *lo_code = At(*lo);
857 *hi = length - 1;
858 *hi_code = At(*hi);
859
860 while ((*hi - *lo) > 1) {
861 intptr_t mid = (*hi - *lo + 1) / 2 + *lo;
862 ASSERT(*lo <= mid);
863 ASSERT(*hi >= mid);
864 ProfileCode* code = At(mid);
865 if (code->start() <= pc) {
866 *lo = mid;
867 *lo_code = code;
868 }
869 if (pc < code->end()) {
870 *hi = mid;
871 *hi_code = code;
811 } 872 }
812 } 873 }
813 return first;
814 }
815
816 static bool CompareUpperBound(uword pc, uword start, uword end) {
817 return pc >= end;
818 }
819
820 static bool CompareLowerBound(uword pc, uword start, uword end) {
821 return end <= pc;
822 }
823
824 void HandleOverlap(ProfileCode* existing,
825 ProfileCode* code,
826 uword start,
827 uword end) {
828 // We should never see overlapping Dart code regions.
829 ASSERT(existing->kind() != ProfileCode::kDartCode);
830 // We should never see overlapping Tag code regions.
831 ASSERT(existing->kind() != ProfileCode::kTagCode);
832 // When code regions overlap, they should be of the same kind.
833 ASSERT(existing->kind() == code->kind());
834 existing->AdjustExtent(start, end);
835 } 874 }
836 875
837 void VerifyOrder() { 876 void VerifyOrder() {
838 const intptr_t length = table_.length(); 877 const intptr_t length = table_.length();
839 if (length == 0) { 878 if (length == 0) {
840 return; 879 return;
841 } 880 }
842 uword last = table_[0]->end(); 881 uword last = table_[0]->end();
843 for (intptr_t i = 1; i < length; i++) { 882 for (intptr_t i = 1; i < length; i++) {
844 ProfileCode* a = table_[i]; 883 ProfileCode* a = table_[i];
(...skipping 1387 matching lines...) Expand 10 before | Expand all | Expand 10 after
2232 // Failed to find a native symbol for pc. 2271 // Failed to find a native symbol for pc.
2233 native_start = pc; 2272 native_start = pc;
2234 } 2273 }
2235 2274
2236 #if defined(HOST_ARCH_ARM) 2275 #if defined(HOST_ARCH_ARM)
2237 // The symbol for a Thumb function will be xxx1, but we may have samples 2276 // The symbol for a Thumb function will be xxx1, but we may have samples
2238 // at function entry which will have pc xxx0. 2277 // at function entry which will have pc xxx0.
2239 native_start &= ~1; 2278 native_start &= ~1;
2240 #endif 2279 #endif
2241 2280
2281 if (native_start > pc) {
2282 // Bogus lookup result.
2283 if (native_name != NULL) {
2284 NativeSymbolResolver::FreeSymbolName(native_name);
2285 native_name = NULL;
2286 }
2287 native_start = pc;
2288 }
2289 if ((pc - native_start) > (32 * KB)) {
2290 // Suspect lookup result. More likely dladdr going off the rails than a
2291 // jumbo function.
2292 if (native_name != NULL) {
2293 NativeSymbolResolver::FreeSymbolName(native_name);
2294 native_name = NULL;
2295 }
2296 native_start = pc;
2297 }
2298
2242 ASSERT(pc >= native_start); 2299 ASSERT(pc >= native_start);
2243 profile_code = new ProfileCode(ProfileCode::kNativeCode, native_start, 2300 profile_code = new ProfileCode(ProfileCode::kNativeCode, native_start,
2244 pc + 1, 0, code); 2301 pc + 1, 0, code);
2245 if (native_name != NULL) { 2302 if (native_name != NULL) {
2246 profile_code->SetName(native_name); 2303 profile_code->SetName(native_name);
2247 NativeSymbolResolver::FreeSymbolName(native_name); 2304 NativeSymbolResolver::FreeSymbolName(native_name);
2248 } 2305 }
2249 2306
2250 RegisterLiveProfileCode(profile_code); 2307 RegisterLiveProfileCode(profile_code);
2251 return profile_code; 2308 return profile_code;
(...skipping 596 matching lines...) Expand 10 before | Expand all | Expand 10 after
2848 // Disable thread interrupts while processing the buffer. 2905 // Disable thread interrupts while processing the buffer.
2849 DisableThreadInterruptsScope dtis(thread); 2906 DisableThreadInterruptsScope dtis(thread);
2850 2907
2851 ClearProfileVisitor clear_profile(isolate); 2908 ClearProfileVisitor clear_profile(isolate);
2852 sample_buffer->VisitSamples(&clear_profile); 2909 sample_buffer->VisitSamples(&clear_profile);
2853 } 2910 }
2854 2911
2855 #endif // !PRODUCT 2912 #endif // !PRODUCT
2856 2913
2857 } // namespace dart 2914 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/profiler_service.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698