1 // Copyright 2006-2008 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 #include "v8.h"
29
30 #include "codegen-inl.h"
31 #include "debug.h"
32
33 namespace v8 {
34 namespace internal {
35
36 #ifdef ENABLE_DEBUGGER_SUPPORT
IsDebugBreakAtReturn()37 bool BreakLocationIterator::IsDebugBreakAtReturn() {
38 return Debug::IsDebugBreakAtReturn(rinfo());
39 }
40
41
SetDebugBreakAtReturn()42 void BreakLocationIterator::SetDebugBreakAtReturn() {
43 // Patch the code changing the return from JS function sequence from
44 // mov sp, fp
45 // ldmia sp!, {fp, lr}
46 // add sp, sp, #4
47 // bx lr
48 // to a call to the debug break return code.
49 // mov lr, pc
50 // ldr pc, [pc, #-4]
51 // <debug break return code entry point address>
52 // bktp 0
53 CodePatcher patcher(rinfo()->pc(), 4);
54 patcher.masm()->mov(v8::internal::lr, v8::internal::pc);
55 patcher.masm()->ldr(v8::internal::pc, MemOperand(v8::internal::pc, -4));
56 patcher.Emit(Debug::debug_break_return()->entry());
57 patcher.masm()->bkpt(0);
58 }
59
60
61 // Restore the JS frame exit code.
ClearDebugBreakAtReturn()62 void BreakLocationIterator::ClearDebugBreakAtReturn() {
63 rinfo()->PatchCode(original_rinfo()->pc(),
64 Assembler::kJSReturnSequenceLength);
65 }
66
67
68 // A debug break in the exit code is identified by a call.
IsDebugBreakAtReturn(RelocInfo * rinfo)69 bool Debug::IsDebugBreakAtReturn(RelocInfo* rinfo) {
70 ASSERT(RelocInfo::IsJSReturn(rinfo->rmode()));
71 return rinfo->IsPatchedReturnSequence();
72 }
73
74
75 #define __ ACCESS_MASM(masm)
76
77
Generate_DebugBreakCallHelper(MacroAssembler * masm,RegList pointer_regs)78 static void Generate_DebugBreakCallHelper(MacroAssembler* masm,
79 RegList pointer_regs) {
80 // Save the content of all general purpose registers in memory. This copy in
81 // memory is later pushed onto the JS expression stack for the fake JS frame
82 // generated and also to the C frame generated on top of that. In the JS
83 // frame ONLY the registers containing pointers will be pushed on the
84 // expression stack. This causes the GC to update these pointers so that
85 // they will have the correct value when returning from the debugger.
86 __ SaveRegistersToMemory(kJSCallerSaved);
87
88 __ EnterInternalFrame();
89
90 // Store the registers containing object pointers on the expression stack to
91 // make sure that these are correctly updated during GC.
92 // Use sp as base to push.
93 __ CopyRegistersFromMemoryToStack(sp, pointer_regs);
94
95 #ifdef DEBUG
96 __ RecordComment("// Calling from debug break to runtime - come in - over");
97 #endif
98 __ mov(r0, Operand(0)); // no arguments
99 __ mov(r1, Operand(ExternalReference::debug_break()));
100
101 CEntryStub ceb(1, ExitFrame::MODE_DEBUG);
102 __ CallStub(&ceb);
103
104 // Restore the register values containing object pointers from the expression
105 // stack in the reverse order as they where pushed.
106 // Use sp as base to pop.
107 __ CopyRegistersFromStackToMemory(sp, r3, pointer_regs);
108
109 __ LeaveInternalFrame();
110
111 // Finally restore all registers.
112 __ RestoreRegistersFromMemory(kJSCallerSaved);
113
114 // Now that the break point has been handled, resume normal execution by
115 // jumping to the target address intended by the caller and that was
116 // overwritten by the address of DebugBreakXXX.
117 __ mov(ip, Operand(ExternalReference(Debug_Address::AfterBreakTarget())));
118 __ ldr(ip, MemOperand(ip));
119 __ Jump(ip);
120 }
121
122
GenerateLoadICDebugBreak(MacroAssembler * masm)123 void Debug::GenerateLoadICDebugBreak(MacroAssembler* masm) {
124 // Calling convention for IC load (from ic-arm.cc).
125 // ----------- S t a t e -------------
126 // -- r0 : receiver
127 // -- r2 : name
128 // -- lr : return address
129 // -- [sp] : receiver
130 // -----------------------------------
131 // Registers r0 and r2 contain objects that need to be pushed on the
132 // expression stack of the fake JS frame.
133 Generate_DebugBreakCallHelper(masm, r0.bit() | r2.bit());
134 }
135
136
GenerateStoreICDebugBreak(MacroAssembler * masm)137 void Debug::GenerateStoreICDebugBreak(MacroAssembler* masm) {
138 // Calling convention for IC store (from ic-arm.cc).
139 // ----------- S t a t e -------------
140 // -- r0 : value
141 // -- r1 : receiver
142 // -- r2 : name
143 // -- lr : return address
144 // -----------------------------------
145 // Registers r0, r1, and r2 contain objects that need to be pushed on the
146 // expression stack of the fake JS frame.
147 Generate_DebugBreakCallHelper(masm, r0.bit() | r1.bit() | r2.bit());
148 }
149
150
GenerateKeyedLoadICDebugBreak(MacroAssembler * masm)151 void Debug::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) {
152 // ---------- S t a t e --------------
153 // -- lr : return address
154 // -- sp[0] : key
155 // -- sp[4] : receiver
156 Generate_DebugBreakCallHelper(masm, 0);
157 }
158
159
GenerateKeyedStoreICDebugBreak(MacroAssembler * masm)160 void Debug::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) {
161 // ---------- S t a t e --------------
162 // -- lr : return address
163 // -- sp[0] : key
164 // -- sp[4] : receiver
165 Generate_DebugBreakCallHelper(masm, 0);
166 }
167
168
GenerateCallICDebugBreak(MacroAssembler * masm)169 void Debug::GenerateCallICDebugBreak(MacroAssembler* masm) {
170 // Calling convention for IC call (from ic-arm.cc)
171 // ----------- S t a t e -------------
172 // -- r0: number of arguments
173 // -- r1: receiver
174 // -- lr: return address
175 // -----------------------------------
176 // Register r1 contains an object that needs to be pushed on the expression
177 // stack of the fake JS frame. r0 is the actual number of arguments not
178 // encoded as a smi, therefore it cannot be on the expression stack of the
179 // fake JS frame as it can easily be an invalid pointer (e.g. 1). r0 will be
180 // pushed on the stack of the C frame and restored from there.
181 Generate_DebugBreakCallHelper(masm, r1.bit());
182 }
183
184
GenerateConstructCallDebugBreak(MacroAssembler * masm)185 void Debug::GenerateConstructCallDebugBreak(MacroAssembler* masm) {
186 // In places other than IC call sites it is expected that r0 is TOS which
187 // is an object - this is not generally the case so this should be used with
188 // care.
189 Generate_DebugBreakCallHelper(masm, r0.bit());
190 }
191
192
GenerateReturnDebugBreak(MacroAssembler * masm)193 void Debug::GenerateReturnDebugBreak(MacroAssembler* masm) {
194 // In places other than IC call sites it is expected that r0 is TOS which
195 // is an object - this is not generally the case so this should be used with
196 // care.
197 Generate_DebugBreakCallHelper(masm, r0.bit());
198 }
199
200
GenerateStubNoRegistersDebugBreak(MacroAssembler * masm)201 void Debug::GenerateStubNoRegistersDebugBreak(MacroAssembler* masm) {
202 // ----------- S t a t e -------------
203 // No registers used on entry.
204 // -----------------------------------
205 Generate_DebugBreakCallHelper(masm, 0);
206 }
207
208
209 #undef __
210
211 #endif // ENABLE_DEBUGGER_SUPPORT
212
213 } } // namespace v8::internal
214