Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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/debugger.h" | 5 #include "vm/debugger.h" |
| 6 | 6 |
| 7 #include "vm/code_generator.h" | 7 #include "vm/code_generator.h" |
| 8 #include "vm/code_patcher.h" | 8 #include "vm/code_patcher.h" |
| 9 #include "vm/compiler.h" | 9 #include "vm/compiler.h" |
| 10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
| (...skipping 803 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 814 event.type = kExceptionThrown; | 814 event.type = kExceptionThrown; |
| 815 event.exception = &exc; | 815 event.exception = &exc; |
| 816 ASSERT(event_handler_ != NULL); | 816 ASSERT(event_handler_ != NULL); |
| 817 (*event_handler_)(&event); | 817 (*event_handler_)(&event); |
| 818 stack_trace_ = NULL; | 818 stack_trace_ = NULL; |
| 819 obj_cache_ = NULL; // Remote object cache is zone allocated. | 819 obj_cache_ = NULL; // Remote object cache is zone allocated. |
| 820 } | 820 } |
| 821 | 821 |
| 822 | 822 |
| 823 CodeBreakpoint* Debugger::MakeCodeBreakpoint(const Function& func, | 823 CodeBreakpoint* Debugger::MakeCodeBreakpoint(const Function& func, |
| 824 intptr_t token_pos) { | 824 intptr_t first_token_pos, |
| 825 intptr_t last_token_pos) { | |
| 825 ASSERT(func.HasCode()); | 826 ASSERT(func.HasCode()); |
| 826 ASSERT(!func.HasOptimizedCode()); | 827 ASSERT(!func.HasOptimizedCode()); |
| 827 Code& code = Code::Handle(func.unoptimized_code()); | 828 Code& code = Code::Handle(func.unoptimized_code()); |
| 828 ASSERT(!code.IsNull()); | 829 ASSERT(!code.IsNull()); |
| 829 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); | 830 PcDescriptors& desc = PcDescriptors::Handle(code.pc_descriptors()); |
| 831 // We attempt to find the PC descriptor that is closest to the | |
| 832 // beginning of the token range, in terms of native code address. If we | |
| 833 // don't find a PC descriptor within the given range, we pick the | |
| 834 // neares one to the beginning of the range, in terms of token position. | |
|
siva
2012/06/27 02:00:31
nearest
hausner
2012/06/27 17:09:18
Done.
| |
| 830 intptr_t best_fit_index = -1; | 835 intptr_t best_fit_index = -1; |
| 831 intptr_t best_fit = INT_MAX; | 836 intptr_t best_fit = INT_MAX; |
| 837 uword lowest_pc = UINTPTR_MAX; | |
| 838 intptr_t lowest_pc_index = -1; | |
| 832 for (int i = 0; i < desc.Length(); i++) { | 839 for (int i = 0; i < desc.Length(); i++) { |
| 833 intptr_t desc_token_pos = desc.TokenIndex(i); | 840 intptr_t desc_token_pos = desc.TokenIndex(i); |
| 834 if (desc_token_pos < token_pos) { | 841 if (desc_token_pos < first_token_pos) { |
| 835 continue; | 842 continue; |
| 836 } | 843 } |
| 837 PcDescriptors::Kind kind = desc.DescriptorKind(i); | 844 PcDescriptors::Kind kind = desc.DescriptorKind(i); |
| 838 if ((kind == PcDescriptors::kIcCall) || | 845 if ((kind == PcDescriptors::kIcCall) || |
| 839 (kind == PcDescriptors::kFuncCall) || | 846 (kind == PcDescriptors::kFuncCall) || |
| 840 (kind == PcDescriptors::kReturn)) { | 847 (kind == PcDescriptors::kReturn)) { |
| 841 if ((desc_token_pos - token_pos) < best_fit) { | 848 if ((desc_token_pos - first_token_pos) < best_fit) { |
| 842 best_fit = desc_token_pos - token_pos; | 849 best_fit = desc_token_pos - first_token_pos; |
| 843 ASSERT(best_fit >= 0); | 850 ASSERT(best_fit >= 0); |
| 844 best_fit_index = i; | 851 best_fit_index = i; |
| 845 } | 852 } |
| 853 if ((first_token_pos <= desc_token_pos) && | |
| 854 (desc_token_pos <= last_token_pos) && | |
| 855 (desc.PC(i) < lowest_pc)) { | |
| 856 lowest_pc = desc.PC(i); | |
| 857 lowest_pc_index = i; | |
| 858 } | |
| 846 } | 859 } |
| 847 } | 860 } |
| 861 if (lowest_pc_index >= 0) { | |
| 862 // We found the the pc descriptor within the given token range that | |
| 863 // has the lowest execution address. This is the first possible | |
| 864 // breakpoint on the line. We use this instead of the nearest | |
| 865 // PC descriptor measured in token index distance. | |
| 866 best_fit_index = lowest_pc_index; | |
| 867 } | |
| 848 if (best_fit_index >= 0) { | 868 if (best_fit_index >= 0) { |
| 849 CodeBreakpoint* bpt = GetCodeBreakpoint(desc.PC(best_fit_index)); | 869 CodeBreakpoint* bpt = GetCodeBreakpoint(desc.PC(best_fit_index)); |
| 850 // We should only ever have one code breakpoint at the same address. | 870 // We should only ever have one code breakpoint at the same address. |
| 851 // If we find an existing breakpoint, it must be an internal one which | 871 // If we find an existing breakpoint, it must be an internal one which |
| 852 // is used for stepping. | 872 // is used for stepping. |
| 853 if (bpt != NULL) { | 873 if (bpt != NULL) { |
| 854 ASSERT(bpt->src_bpt() == NULL); | 874 ASSERT(bpt->src_bpt() == NULL); |
| 855 return bpt; | 875 return bpt; |
| 856 } | 876 } |
| 857 | 877 |
| 858 bpt = new CodeBreakpoint(func, best_fit_index); | 878 bpt = new CodeBreakpoint(func, best_fit_index); |
| 859 if (verbose) { | 879 if (verbose) { |
| 860 OS::Print("Setting breakpoint in function '%s' (%s:%d) (PC %p)\n", | 880 OS::Print("Setting breakpoint in function '%s' (%s:%d) (PC %p)\n", |
| 861 String::Handle(func.name()).ToCString(), | 881 String::Handle(func.name()).ToCString(), |
| 862 String::Handle(bpt->SourceUrl()).ToCString(), | 882 String::Handle(bpt->SourceUrl()).ToCString(), |
| 863 bpt->LineNumber(), | 883 bpt->LineNumber(), |
| 864 bpt->pc()); | 884 bpt->pc()); |
| 865 } | 885 } |
| 866 RegisterCodeBreakpoint(bpt); | 886 RegisterCodeBreakpoint(bpt); |
| 867 return bpt; | 887 return bpt; |
| 868 } | 888 } |
| 869 return NULL; | 889 return NULL; |
| 870 } | 890 } |
| 871 | 891 |
| 872 | 892 |
| 873 SourceBreakpoint* Debugger::SetBreakpoint(const Function& target_function, | 893 SourceBreakpoint* Debugger::SetBreakpoint(const Function& target_function, |
| 874 intptr_t token_pos) { | 894 intptr_t first_token_pos, |
| 875 if ((token_pos < target_function.token_pos()) || | 895 intptr_t last_token_pos) { |
| 876 (target_function.end_token_pos() <= token_pos)) { | 896 if ((last_token_pos < target_function.token_pos()) || |
| 897 (target_function.end_token_pos() < first_token_pos)) { | |
| 877 // The given token position is not within the target function. | 898 // The given token position is not within the target function. |
| 878 return NULL; | 899 return NULL; |
| 879 } | 900 } |
| 880 EnsureFunctionIsDeoptimized(target_function); | 901 EnsureFunctionIsDeoptimized(target_function); |
| 881 SourceBreakpoint* bpt = GetSourceBreakpoint(target_function, token_pos); | 902 SourceBreakpoint* bpt = GetSourceBreakpoint(target_function, first_token_pos); |
| 882 if (bpt != NULL) { | 903 if (bpt != NULL) { |
| 883 // A breakpoint for this location already exists, return it. | 904 // A breakpoint for this location already exists, return it. |
| 884 return bpt; | 905 return bpt; |
| 885 } | 906 } |
| 886 bpt = new SourceBreakpoint(nextId(), target_function, token_pos); | 907 bpt = new SourceBreakpoint(nextId(), target_function, first_token_pos); |
| 887 RegisterSourceBreakpoint(bpt); | 908 RegisterSourceBreakpoint(bpt); |
| 888 if (verbose && !target_function.HasCode()) { | 909 if (verbose && !target_function.HasCode()) { |
| 889 OS::Print("Registering breakpoint for " | 910 OS::Print("Registering breakpoint for " |
| 890 "uncompiled function '%s' at line %d\n", | 911 "uncompiled function '%s' at line %d\n", |
| 891 target_function.ToFullyQualifiedCString(), | 912 target_function.ToFullyQualifiedCString(), |
| 892 bpt->LineNumber()); | 913 bpt->LineNumber()); |
| 893 } | 914 } |
| 894 | 915 |
| 895 if (target_function.HasCode()) { | 916 if (target_function.HasCode()) { |
| 896 CodeBreakpoint* cbpt = MakeCodeBreakpoint(target_function, token_pos); | 917 CodeBreakpoint* cbpt = |
| 918 MakeCodeBreakpoint(target_function, first_token_pos, last_token_pos); | |
| 897 if (cbpt != NULL) { | 919 if (cbpt != NULL) { |
| 898 ASSERT(cbpt->src_bpt() == NULL); | 920 ASSERT(cbpt->src_bpt() == NULL); |
| 899 cbpt->set_src_bpt(bpt); | 921 cbpt->set_src_bpt(bpt); |
| 900 SignalBpResolved(bpt); | 922 SignalBpResolved(bpt); |
| 901 } else { | 923 } else { |
| 902 if (verbose) { | 924 if (verbose) { |
| 903 OS::Print("Failed to set breakpoint at '%s' line %d\n", | 925 OS::Print("Failed to set breakpoint at '%s' line %d\n", |
| 904 String::Handle(bpt->SourceUrl()).ToCString(), | 926 String::Handle(bpt->SourceUrl()).ToCString(), |
| 905 bpt->LineNumber()); | 927 bpt->LineNumber()); |
| 906 } | 928 } |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 924 } | 946 } |
| 925 } | 947 } |
| 926 cbpt = cbpt->next(); | 948 cbpt = cbpt->next(); |
| 927 } | 949 } |
| 928 } | 950 } |
| 929 | 951 |
| 930 | 952 |
| 931 SourceBreakpoint* Debugger::SetBreakpointAtEntry( | 953 SourceBreakpoint* Debugger::SetBreakpointAtEntry( |
| 932 const Function& target_function) { | 954 const Function& target_function) { |
| 933 ASSERT(!target_function.IsNull()); | 955 ASSERT(!target_function.IsNull()); |
| 934 return SetBreakpoint(target_function, target_function.token_pos()); | 956 return SetBreakpoint(target_function, |
| 957 target_function.token_pos(), | |
| 958 target_function.end_token_pos()); | |
| 935 } | 959 } |
| 936 | 960 |
| 937 | 961 |
| 938 SourceBreakpoint* Debugger::SetBreakpointAtLine(const String& script_url, | 962 SourceBreakpoint* Debugger::SetBreakpointAtLine(const String& script_url, |
| 939 intptr_t line_number) { | 963 intptr_t line_number) { |
| 940 Library& lib = Library::Handle(); | 964 Library& lib = Library::Handle(); |
| 941 Script& script = Script::Handle(); | 965 Script& script = Script::Handle(); |
| 942 const GrowableObjectArray& libs = | 966 const GrowableObjectArray& libs = |
| 943 GrowableObjectArray::Handle(isolate_->object_store()->libraries()); | 967 GrowableObjectArray::Handle(isolate_->object_store()->libraries()); |
| 944 for (int i = 0; i < libs.Length(); i++) { | 968 for (int i = 0; i < libs.Length(); i++) { |
| 945 lib ^= libs.At(i); | 969 lib ^= libs.At(i); |
| 946 script = lib.LookupScript(script_url); | 970 script = lib.LookupScript(script_url); |
| 947 if (!script.IsNull()) { | 971 if (!script.IsNull()) { |
| 948 break; | 972 break; |
| 949 } | 973 } |
| 950 } | 974 } |
| 951 if (script.IsNull()) { | 975 if (script.IsNull()) { |
| 952 if (verbose) { | 976 if (verbose) { |
| 953 OS::Print("Failed to find script with url '%s'\n", | 977 OS::Print("Failed to find script with url '%s'\n", |
| 954 script_url.ToCString()); | 978 script_url.ToCString()); |
| 955 } | 979 } |
| 956 return NULL; | 980 return NULL; |
| 957 } | 981 } |
| 958 intptr_t token_pos_at_line = script.TokenIndexAtLine(line_number); | 982 intptr_t first_token_idx, last_token_idx; |
| 959 if (token_pos_at_line < 0) { | 983 script.TokenRangeAtLine(line_number, &first_token_idx, &last_token_idx); |
| 984 if (first_token_idx < 0) { | |
| 960 // Script does not contain the given line number. | 985 // Script does not contain the given line number. |
| 961 if (verbose) { | 986 if (verbose) { |
| 962 OS::Print("Script '%s' does not contain line number %d\n", | 987 OS::Print("Script '%s' does not contain line number %d\n", |
| 963 script_url.ToCString(), line_number); | 988 script_url.ToCString(), line_number); |
| 964 } | 989 } |
| 965 return NULL; | 990 return NULL; |
| 966 } | 991 } |
| 967 const Function& func = | 992 const Function& func = |
| 968 Function::Handle(lib.LookupFunctionInScript(script, token_pos_at_line)); | 993 Function::Handle(lib.LookupFunctionInScript(script, first_token_idx)); |
| 969 if (func.IsNull()) { | 994 if (func.IsNull()) { |
| 970 if (verbose) { | 995 if (verbose) { |
| 971 OS::Print("No executable code at line %d in '%s'\n", | 996 OS::Print("No executable code at line %d in '%s'\n", |
| 972 line_number, script_url.ToCString()); | 997 line_number, script_url.ToCString()); |
| 973 } | 998 } |
| 974 return NULL; | 999 return NULL; |
| 975 } | 1000 } |
| 976 return SetBreakpoint(func, token_pos_at_line); | 1001 if (last_token_idx < 0) { |
| 1002 // The token at first_token_index is past the requested source line. | |
| 1003 // Set the breakpoint at the closest position after that line. | |
| 1004 last_token_idx = func.end_token_pos(); | |
| 1005 } | |
| 1006 return SetBreakpoint(func, first_token_idx, last_token_idx); | |
| 977 } | 1007 } |
| 978 | 1008 |
| 979 | 1009 |
| 980 intptr_t Debugger::CacheObject(const Object& obj) { | 1010 intptr_t Debugger::CacheObject(const Object& obj) { |
| 981 ASSERT(obj_cache_ != NULL); | 1011 ASSERT(obj_cache_ != NULL); |
| 982 return obj_cache_->AddObject(obj); | 1012 return obj_cache_->AddObject(obj); |
| 983 } | 1013 } |
| 984 | 1014 |
| 985 | 1015 |
| 986 bool Debugger::IsValidObjectId(intptr_t obj_id) { | 1016 bool Debugger::IsValidObjectId(intptr_t obj_id) { |
| (...skipping 398 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1385 OS::Print("Resetting pending breakpoint to function %s\n", | 1415 OS::Print("Resetting pending breakpoint to function %s\n", |
| 1386 closure.ToFullyQualifiedCString()); | 1416 closure.ToFullyQualifiedCString()); |
| 1387 } | 1417 } |
| 1388 bpt->set_function(closure); | 1418 bpt->set_function(closure); |
| 1389 } else { | 1419 } else { |
| 1390 if (verbose) { | 1420 if (verbose) { |
| 1391 OS::Print("Enable pending breakpoint for function '%s'\n", | 1421 OS::Print("Enable pending breakpoint for function '%s'\n", |
| 1392 String::Handle(lookup_function.name()).ToCString()); | 1422 String::Handle(lookup_function.name()).ToCString()); |
| 1393 } | 1423 } |
| 1394 // Set breakpoint in newly compiled code of function func. | 1424 // Set breakpoint in newly compiled code of function func. |
| 1395 CodeBreakpoint* cbpt = MakeCodeBreakpoint(func, bpt->token_pos()); | 1425 CodeBreakpoint* cbpt = |
| 1426 MakeCodeBreakpoint(func, bpt->token_pos(), func.end_token_pos()); | |
| 1396 if (cbpt != NULL) { | 1427 if (cbpt != NULL) { |
| 1397 cbpt->set_src_bpt(bpt); | 1428 cbpt->set_src_bpt(bpt); |
| 1398 SignalBpResolved(bpt); | 1429 SignalBpResolved(bpt); |
| 1399 } | 1430 } |
| 1400 } | 1431 } |
| 1401 bpt->Enable(); // Enables the code breakpoint as well. | 1432 bpt->Enable(); // Enables the code breakpoint as well. |
| 1402 } | 1433 } |
| 1403 bpt = bpt->next(); | 1434 bpt = bpt->next(); |
| 1404 } | 1435 } |
| 1405 } | 1436 } |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1517 } | 1548 } |
| 1518 | 1549 |
| 1519 | 1550 |
| 1520 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { | 1551 void Debugger::RegisterCodeBreakpoint(CodeBreakpoint* bpt) { |
| 1521 ASSERT(bpt->next() == NULL); | 1552 ASSERT(bpt->next() == NULL); |
| 1522 bpt->set_next(code_breakpoints_); | 1553 bpt->set_next(code_breakpoints_); |
| 1523 code_breakpoints_ = bpt; | 1554 code_breakpoints_ = bpt; |
| 1524 } | 1555 } |
| 1525 | 1556 |
| 1526 } // namespace dart | 1557 } // namespace dart |
| OLD | NEW |