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

Side by Side Diff: src/x87/debug-x87.cc

Issue 1236023007: X87: Debugger: use debug break slots to break at function exit. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years, 5 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 | « src/x87/assembler-x87-inl.h ('k') | src/x87/full-codegen-x87.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "src/v8.h" 5 #include "src/v8.h"
6 6
7 #if V8_TARGET_ARCH_X87 7 #if V8_TARGET_ARCH_X87
8 8
9 #include "src/codegen.h" 9 #include "src/codegen.h"
10 #include "src/debug.h" 10 #include "src/debug.h"
11 11
12 12
13 namespace v8 { 13 namespace v8 {
14 namespace internal { 14 namespace internal {
15 15
16 // Patch the code at the current PC with a call to the target address. 16 #define __ ACCESS_MASM(masm)
17 // Additional guard int3 instructions can be added if required.
18 void PatchCodeWithCall(Address pc, Address target, int guard_bytes) {
19 // Call instruction takes up 5 bytes and int3 takes up one byte.
20 static const int kCallCodeSize = 5;
21 int code_size = kCallCodeSize + guard_bytes;
22 17
23 // Create a code patcher.
24 CodePatcher patcher(pc, code_size);
25 18
26 // Add a label for checking the size of the code used for returning. 19 void EmitDebugBreakSlot(MacroAssembler* masm) {
27 #ifdef DEBUG
28 Label check_codesize; 20 Label check_codesize;
29 patcher.masm()->bind(&check_codesize); 21 __ bind(&check_codesize);
30 #endif 22 __ Nop(Assembler::kDebugBreakSlotLength);
31 23 DCHECK_EQ(Assembler::kDebugBreakSlotLength,
32 // Patch the code. 24 masm->SizeOfCodeGeneratedSince(&check_codesize));
33 patcher.masm()->call(target, RelocInfo::NONE32);
34
35 // Check that the size of the code generated is as expected.
36 DCHECK_EQ(kCallCodeSize,
37 patcher.masm()->SizeOfCodeGeneratedSince(&check_codesize));
38
39 // Add the requested number of int3 instructions after the call.
40 DCHECK_GE(guard_bytes, 0);
41 for (int i = 0; i < guard_bytes; i++) {
42 patcher.masm()->int3();
43 }
44
45 CpuFeatures::FlushICache(pc, code_size);
46 } 25 }
47 26
48 27
49 // Patch the JS frame exit code with a debug break call. See 28 void DebugCodegen::GenerateSlot(MacroAssembler* masm, RelocInfo::Mode mode,
50 // CodeGenerator::VisitReturnStatement and VirtualFrame::Exit in codegen-x87.cc 29 int call_argc) {
51 // for the precise return instructions sequence. 30 // Generate enough nop's to make space for a call instruction.
52 void BreakLocation::SetDebugBreakAtReturn() { 31 masm->RecordDebugBreakSlot(mode, call_argc);
53 DCHECK(Assembler::kJSReturnSequenceLength >= 32 EmitDebugBreakSlot(masm);
54 Assembler::kCallInstructionLength);
55 PatchCodeWithCall(
56 pc(), debug_info_->GetIsolate()->builtins()->Return_DebugBreak()->entry(),
57 Assembler::kJSReturnSequenceLength - Assembler::kCallInstructionLength);
58 } 33 }
59 34
60 35
61 void BreakLocation::SetDebugBreakAtSlot() { 36 void DebugCodegen::ClearDebugBreakSlot(Address pc) {
62 DCHECK(IsDebugBreakSlot()); 37 CodePatcher patcher(pc, Assembler::kDebugBreakSlotLength);
63 Isolate* isolate = debug_info_->GetIsolate(); 38 EmitDebugBreakSlot(patcher.masm());
64 PatchCodeWithCall(
65 pc(), isolate->builtins()->Slot_DebugBreak()->entry(),
66 Assembler::kDebugBreakSlotLength - Assembler::kCallInstructionLength);
67 } 39 }
68 40
69 41
70 #define __ ACCESS_MASM(masm) 42 void DebugCodegen::PatchDebugBreakSlot(Address pc, Handle<Code> code) {
43 DCHECK_EQ(Code::BUILTIN, code->kind());
44 static const int kSize = Assembler::kDebugBreakSlotLength;
45 CodePatcher patcher(pc, kSize);
71 46
72 static void Generate_DebugBreakCallHelper(MacroAssembler* masm, 47 // Add a label for checking the size of the code used for returning.
73 RegList object_regs) { 48 Label check_codesize;
49 patcher.masm()->bind(&check_codesize);
50 patcher.masm()->call(code->entry(), RelocInfo::NONE32);
51 // Check that the size of the code generated is as expected.
52 DCHECK_EQ(kSize, patcher.masm()->SizeOfCodeGeneratedSince(&check_codesize));
53 }
54
55
56 void DebugCodegen::GenerateDebugBreakStub(MacroAssembler* masm,
57 DebugBreakCallHelperMode mode) {
58 __ RecordComment("Debug break");
59
74 // Enter an internal frame. 60 // Enter an internal frame.
75 { 61 {
76 FrameScope scope(masm, StackFrame::INTERNAL); 62 FrameScope scope(masm, StackFrame::INTERNAL);
77 63
78 // Load padding words on stack. 64 // Load padding words on stack.
79 for (int i = 0; i < LiveEdit::kFramePaddingInitialSize; i++) { 65 for (int i = 0; i < LiveEdit::kFramePaddingInitialSize; i++) {
80 __ push(Immediate(Smi::FromInt(LiveEdit::kFramePaddingValue))); 66 __ push(Immediate(Smi::FromInt(LiveEdit::kFramePaddingValue)));
81 } 67 }
82 __ push(Immediate(Smi::FromInt(LiveEdit::kFramePaddingInitialSize))); 68 __ push(Immediate(Smi::FromInt(LiveEdit::kFramePaddingInitialSize)));
83 69
84 // Store the registers containing live values on the expression stack to 70 if (mode == SAVE_RESULT_REGISTER) __ push(eax);
85 // make sure that these are correctly updated during GC. Non object values
86 // are stored as a smi causing it to be untouched by GC.
87 DCHECK((object_regs & ~kJSCallerSaved) == 0);
88 for (int i = 0; i < kNumJSCallerSaved; i++) {
89 int r = JSCallerSavedCode(i);
90 Register reg = { r };
91 if ((object_regs & (1 << r)) != 0) {
92 __ push(reg);
93 }
94 }
95 71
96 #ifdef DEBUG
97 __ RecordComment("// Calling from debug break to runtime - come in - over");
98 #endif
99 __ Move(eax, Immediate(0)); // No arguments. 72 __ Move(eax, Immediate(0)); // No arguments.
100 __ mov(ebx, Immediate(ExternalReference::debug_break(masm->isolate()))); 73 __ mov(ebx, Immediate(ExternalReference::debug_break(masm->isolate())));
101 74
102 CEntryStub ceb(masm->isolate(), 1); 75 CEntryStub ceb(masm->isolate(), 1);
103 __ CallStub(&ceb); 76 __ CallStub(&ceb);
104 77
105 // Automatically find register that could be used after register restore. 78 if (FLAG_debug_code) {
106 // We need one register for padding skip instructions. 79 for (int i = 0; i < kNumJSCallerSaved; ++i) {
107 Register unused_reg = { -1 }; 80 Register reg = {JSCallerSavedCode(i)};
108
109 // Restore the register values containing object pointers from the
110 // expression stack.
111 for (int i = kNumJSCallerSaved; --i >= 0;) {
112 int r = JSCallerSavedCode(i);
113 Register reg = { r };
114 if (FLAG_debug_code) {
115 __ Move(reg, Immediate(kDebugZapValue)); 81 __ Move(reg, Immediate(kDebugZapValue));
116 } 82 }
117 bool taken = reg.code() == esi.code();
118 if ((object_regs & (1 << r)) != 0) {
119 __ pop(reg);
120 taken = true;
121 }
122 if (!taken) {
123 unused_reg = reg;
124 }
125 } 83 }
126 84
127 DCHECK(unused_reg.code() != -1); 85 if (mode == SAVE_RESULT_REGISTER) __ pop(eax);
128 86
129 // Read current padding counter and skip corresponding number of words. 87 __ pop(ebx);
130 __ pop(unused_reg);
131 // We divide stored value by 2 (untagging) and multiply it by word's size. 88 // We divide stored value by 2 (untagging) and multiply it by word's size.
132 STATIC_ASSERT(kSmiTagSize == 1 && kSmiShiftSize == 0); 89 STATIC_ASSERT(kSmiTagSize == 1 && kSmiShiftSize == 0);
133 __ lea(esp, Operand(esp, unused_reg, times_half_pointer_size, 0)); 90 __ lea(esp, Operand(esp, ebx, times_half_pointer_size, 0));
134 91
135 // Get rid of the internal frame. 92 // Get rid of the internal frame.
136 } 93 }
137 94
138 // This call did not replace a call , so there will be an unwanted 95 // This call did not replace a call , so there will be an unwanted
139 // return address left on the stack. Here we get rid of that. 96 // return address left on the stack. Here we get rid of that.
140 __ add(esp, Immediate(kPointerSize)); 97 __ add(esp, Immediate(kPointerSize));
141 98
142 // Now that the break point has been handled, resume normal execution by 99 // Now that the break point has been handled, resume normal execution by
143 // jumping to the target address intended by the caller and that was 100 // jumping to the target address intended by the caller and that was
144 // overwritten by the address of DebugBreakXXX. 101 // overwritten by the address of DebugBreakXXX.
145 ExternalReference after_break_target = 102 ExternalReference after_break_target =
146 ExternalReference::debug_after_break_target_address(masm->isolate()); 103 ExternalReference::debug_after_break_target_address(masm->isolate());
147 __ jmp(Operand::StaticVariable(after_break_target)); 104 __ jmp(Operand::StaticVariable(after_break_target));
148 } 105 }
149 106
150 107
151 void DebugCodegen::GenerateReturnDebugBreak(MacroAssembler* masm) {
152 // Register state just before return from JS function (from codegen-x87.cc).
153 // ----------- S t a t e -------------
154 // -- eax: return value
155 // -----------------------------------
156 Generate_DebugBreakCallHelper(masm, eax.bit());
157 }
158
159
160 void DebugCodegen::GenerateSlot(MacroAssembler* masm,
161 DebugCodegen::SlotLocation location,
162 int call_argc) {
163 // Generate enough nop's to make space for a call instruction.
164 Label check_codesize;
165 __ bind(&check_codesize);
166 RecordRelocInfo(masm, location, call_argc);
167 __ Nop(Assembler::kDebugBreakSlotLength);
168 DCHECK_EQ(Assembler::kDebugBreakSlotLength,
169 masm->SizeOfCodeGeneratedSince(&check_codesize));
170 }
171
172
173 void DebugCodegen::GenerateSlotDebugBreak(MacroAssembler* masm) {
174 Generate_DebugBreakCallHelper(masm, 0);
175 }
176
177
178 void DebugCodegen::GeneratePlainReturnLiveEdit(MacroAssembler* masm) { 108 void DebugCodegen::GeneratePlainReturnLiveEdit(MacroAssembler* masm) {
179 masm->ret(0); 109 masm->ret(0);
180 } 110 }
181 111
182 112
183 void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) { 113 void DebugCodegen::GenerateFrameDropperLiveEdit(MacroAssembler* masm) {
184 ExternalReference restarter_frame_function_slot = 114 ExternalReference restarter_frame_function_slot =
185 ExternalReference::debug_restarter_frame_function_pointer_address( 115 ExternalReference::debug_restarter_frame_function_pointer_address(
186 masm->isolate()); 116 masm->isolate());
187 __ mov(Operand::StaticVariable(restarter_frame_function_slot), Immediate(0)); 117 __ mov(Operand::StaticVariable(restarter_frame_function_slot), Immediate(0));
(...skipping 18 matching lines...) Expand all
206 136
207 137
208 const bool LiveEdit::kFrameDropperSupported = true; 138 const bool LiveEdit::kFrameDropperSupported = true;
209 139
210 #undef __ 140 #undef __
211 141
212 } // namespace internal 142 } // namespace internal
213 } // namespace v8 143 } // namespace v8
214 144
215 #endif // V8_TARGET_ARCH_X87 145 #endif // V8_TARGET_ARCH_X87
OLDNEW
« no previous file with comments | « src/x87/assembler-x87-inl.h ('k') | src/x87/full-codegen-x87.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698