debug-arm.cc revision 80d68eab642096c1a48b6474d6ec33064b0ad1f5
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#if defined(V8_TARGET_ARCH_ARM) 31 32#include "codegen-inl.h" 33#include "debug.h" 34 35namespace v8 { 36namespace internal { 37 38#ifdef ENABLE_DEBUGGER_SUPPORT 39bool BreakLocationIterator::IsDebugBreakAtReturn() { 40 return Debug::IsDebugBreakAtReturn(rinfo()); 41} 42 43 44void BreakLocationIterator::SetDebugBreakAtReturn() { 45 // Patch the code changing the return from JS function sequence from 46 // mov sp, fp 47 // ldmia sp!, {fp, lr} 48 // add sp, sp, #4 49 // bx lr 50 // to a call to the debug break return code. 51 // #if USE_BLX 52 // ldr ip, [pc, #0] 53 // blx ip 54 // #else 55 // mov lr, pc 56 // ldr pc, [pc, #-4] 57 // #endif 58 // <debug break return code entry point address> 59 // bktp 0 60 CodePatcher patcher(rinfo()->pc(), Assembler::kJSReturnSequenceInstructions); 61#ifdef USE_BLX 62 patcher.masm()->ldr(v8::internal::ip, MemOperand(v8::internal::pc, 0)); 63 patcher.masm()->blx(v8::internal::ip); 64#else 65 patcher.masm()->mov(v8::internal::lr, v8::internal::pc); 66 patcher.masm()->ldr(v8::internal::pc, MemOperand(v8::internal::pc, -4)); 67#endif 68 patcher.Emit(Debug::debug_break_return()->entry()); 69 patcher.masm()->bkpt(0); 70} 71 72 73// Restore the JS frame exit code. 74void BreakLocationIterator::ClearDebugBreakAtReturn() { 75 rinfo()->PatchCode(original_rinfo()->pc(), 76 Assembler::kJSReturnSequenceInstructions); 77} 78 79 80// A debug break in the frame exit code is identified by the JS frame exit code 81// having been patched with a call instruction. 82bool Debug::IsDebugBreakAtReturn(RelocInfo* rinfo) { 83 ASSERT(RelocInfo::IsJSReturn(rinfo->rmode())); 84 return rinfo->IsPatchedReturnSequence(); 85} 86 87 88bool BreakLocationIterator::IsDebugBreakAtSlot() { 89 ASSERT(IsDebugBreakSlot()); 90 // Check whether the debug break slot instructions have been patched. 91 return rinfo()->IsPatchedDebugBreakSlotSequence(); 92} 93 94 95void BreakLocationIterator::SetDebugBreakAtSlot() { 96 ASSERT(IsDebugBreakSlot()); 97 // Patch the code changing the debug break slot code from 98 // mov r2, r2 99 // mov r2, r2 100 // mov r2, r2 101 // to a call to the debug break slot code. 102 // #if USE_BLX 103 // ldr ip, [pc, #0] 104 // blx ip 105 // #else 106 // mov lr, pc 107 // ldr pc, [pc, #-4] 108 // #endif 109 // <debug break slot code entry point address> 110 CodePatcher patcher(rinfo()->pc(), Assembler::kDebugBreakSlotInstructions); 111#ifdef USE_BLX 112 patcher.masm()->ldr(v8::internal::ip, MemOperand(v8::internal::pc, 0)); 113 patcher.masm()->blx(v8::internal::ip); 114#else 115 patcher.masm()->mov(v8::internal::lr, v8::internal::pc); 116 patcher.masm()->ldr(v8::internal::pc, MemOperand(v8::internal::pc, -4)); 117#endif 118 patcher.Emit(Debug::debug_break_return()->entry()); 119} 120 121 122void BreakLocationIterator::ClearDebugBreakAtSlot() { 123 ASSERT(IsDebugBreakSlot()); 124 rinfo()->PatchCode(original_rinfo()->pc(), 125 Assembler::kDebugBreakSlotInstructions); 126} 127 128 129#define __ ACCESS_MASM(masm) 130 131 132static void Generate_DebugBreakCallHelper(MacroAssembler* masm, 133 RegList object_regs, 134 RegList non_object_regs) { 135 __ EnterInternalFrame(); 136 137 // Store the registers containing live values on the expression stack to 138 // make sure that these are correctly updated during GC. Non object values 139 // are stored as a smi causing it to be untouched by GC. 140 ASSERT((object_regs & ~kJSCallerSaved) == 0); 141 ASSERT((non_object_regs & ~kJSCallerSaved) == 0); 142 ASSERT((object_regs & non_object_regs) == 0); 143 if ((object_regs | non_object_regs) != 0) { 144 for (int i = 0; i < kNumJSCallerSaved; i++) { 145 int r = JSCallerSavedCode(i); 146 Register reg = { r }; 147 if ((non_object_regs & (1 << r)) != 0) { 148 if (FLAG_debug_code) { 149 __ tst(reg, Operand(0xc0000000)); 150 __ Assert(eq, "Unable to encode value as smi"); 151 } 152 __ mov(reg, Operand(reg, LSL, kSmiTagSize)); 153 } 154 } 155 __ stm(db_w, sp, object_regs | non_object_regs); 156 } 157 158#ifdef DEBUG 159 __ RecordComment("// Calling from debug break to runtime - come in - over"); 160#endif 161 __ mov(r0, Operand(0)); // no arguments 162 __ mov(r1, Operand(ExternalReference::debug_break())); 163 164 CEntryStub ceb(1); 165 __ CallStub(&ceb); 166 167 // Restore the register values from the expression stack. 168 if ((object_regs | non_object_regs) != 0) { 169 __ ldm(ia_w, sp, object_regs | non_object_regs); 170 for (int i = 0; i < kNumJSCallerSaved; i++) { 171 int r = JSCallerSavedCode(i); 172 Register reg = { r }; 173 if ((non_object_regs & (1 << r)) != 0) { 174 __ mov(reg, Operand(reg, LSR, kSmiTagSize)); 175 } 176 if (FLAG_debug_code && 177 (((object_regs |non_object_regs) & (1 << r)) == 0)) { 178 __ mov(reg, Operand(kDebugZapValue)); 179 } 180 } 181 } 182 183 __ LeaveInternalFrame(); 184 185 // Now that the break point has been handled, resume normal execution by 186 // jumping to the target address intended by the caller and that was 187 // overwritten by the address of DebugBreakXXX. 188 __ mov(ip, Operand(ExternalReference(Debug_Address::AfterBreakTarget()))); 189 __ ldr(ip, MemOperand(ip)); 190 __ Jump(ip); 191} 192 193 194void Debug::GenerateLoadICDebugBreak(MacroAssembler* masm) { 195 // Calling convention for IC load (from ic-arm.cc). 196 // ----------- S t a t e ------------- 197 // -- r2 : name 198 // -- lr : return address 199 // -- r0 : receiver 200 // -- [sp] : receiver 201 // ----------------------------------- 202 // Registers r0 and r2 contain objects that need to be pushed on the 203 // expression stack of the fake JS frame. 204 Generate_DebugBreakCallHelper(masm, r0.bit() | r2.bit(), 0); 205} 206 207 208void Debug::GenerateStoreICDebugBreak(MacroAssembler* masm) { 209 // Calling convention for IC store (from ic-arm.cc). 210 // ----------- S t a t e ------------- 211 // -- r0 : value 212 // -- r1 : receiver 213 // -- r2 : name 214 // -- lr : return address 215 // ----------------------------------- 216 // Registers r0, r1, and r2 contain objects that need to be pushed on the 217 // expression stack of the fake JS frame. 218 Generate_DebugBreakCallHelper(masm, r0.bit() | r1.bit() | r2.bit(), 0); 219} 220 221 222void Debug::GenerateKeyedLoadICDebugBreak(MacroAssembler* masm) { 223 // ---------- S t a t e -------------- 224 // -- lr : return address 225 // -- r0 : key 226 // -- r1 : receiver 227 Generate_DebugBreakCallHelper(masm, r0.bit() | r1.bit(), 0); 228} 229 230 231void Debug::GenerateKeyedStoreICDebugBreak(MacroAssembler* masm) { 232 // ---------- S t a t e -------------- 233 // -- r0 : value 234 // -- r1 : key 235 // -- r2 : receiver 236 // -- lr : return address 237 Generate_DebugBreakCallHelper(masm, r0.bit() | r1.bit() | r2.bit(), 0); 238} 239 240 241void Debug::GenerateCallICDebugBreak(MacroAssembler* masm) { 242 // Calling convention for IC call (from ic-arm.cc) 243 // ----------- S t a t e ------------- 244 // -- r2 : name 245 // ----------------------------------- 246 Generate_DebugBreakCallHelper(masm, r2.bit(), 0); 247} 248 249 250void Debug::GenerateConstructCallDebugBreak(MacroAssembler* masm) { 251 // Calling convention for construct call (from builtins-arm.cc) 252 // -- r0 : number of arguments (not smi) 253 // -- r1 : constructor function 254 Generate_DebugBreakCallHelper(masm, r1.bit(), r0.bit()); 255} 256 257 258void Debug::GenerateReturnDebugBreak(MacroAssembler* masm) { 259 // In places other than IC call sites it is expected that r0 is TOS which 260 // is an object - this is not generally the case so this should be used with 261 // care. 262 Generate_DebugBreakCallHelper(masm, r0.bit(), 0); 263} 264 265 266void Debug::GenerateStubNoRegistersDebugBreak(MacroAssembler* masm) { 267 // ----------- S t a t e ------------- 268 // No registers used on entry. 269 // ----------------------------------- 270 Generate_DebugBreakCallHelper(masm, 0, 0); 271} 272 273 274void Debug::GenerateSlot(MacroAssembler* masm) { 275 // Generate enough nop's to make space for a call instruction. Avoid emitting 276 // the constant pool in the debug break slot code. 277 Assembler::BlockConstPoolScope block_const_pool(masm); 278 Label check_codesize; 279 __ bind(&check_codesize); 280 __ RecordDebugBreakSlot(); 281 for (int i = 0; i < Assembler::kDebugBreakSlotInstructions; i++) { 282 __ nop(2); 283 } 284 ASSERT_EQ(Assembler::kDebugBreakSlotInstructions, 285 masm->InstructionsGeneratedSince(&check_codesize)); 286} 287 288 289void Debug::GenerateSlotDebugBreak(MacroAssembler* masm) { 290 // In the places where a debug break slot is inserted no registers can contain 291 // object pointers. 292 Generate_DebugBreakCallHelper(masm, 0, 0); 293} 294 295 296void Debug::GeneratePlainReturnLiveEdit(MacroAssembler* masm) { 297 masm->Abort("LiveEdit frame dropping is not supported on arm"); 298} 299 300 301void Debug::GenerateFrameDropperLiveEdit(MacroAssembler* masm) { 302 masm->Abort("LiveEdit frame dropping is not supported on arm"); 303} 304 305const bool Debug::kFrameDropperSupported = false; 306 307#undef __ 308 309 310 311#endif // ENABLE_DEBUGGER_SUPPORT 312 313} } // namespace v8::internal 314 315#endif // V8_TARGET_ARCH_ARM 316