4 ; Breakpoint handling (MDW)
6 ; © 1994-1998 Straylight
9 ;----- Licensing note -------------------------------------------------------
11 ; This file is part of Straylight's Sledgehammer debugger.
13 ; Sledgehammer is free software; you can redistribute it and/or modify
14 ; it under the terms of the GNU General Public License as published by
15 ; the Free Software Foundation; either version 2, or (at your option)
18 ; Sledgehammer is distributed in the hope that it will be useful,
19 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ; GNU General Public License for more details.
23 ; You should have received a copy of the GNU General Public License
24 ; along with Sledgehammer. If not, write to the Free Software Foundation,
25 ; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 ;----- Things not to forget -------------------------------------------------
29 ; When removing a break point, ensure instruction is still our branch
31 ;----- Standard header ------------------------------------------------------
37 ;----- External dependencies ------------------------------------------------
43 ;----- Main code ------------------------------------------------------------
45 AREA |Hammer$$Code|,CODE,READONLY
49 ; On entry: R0 == address to set breakpoint
51 ; On exit: May return error
53 ; Use: Sets a breakpoint at the given location, giving it the
54 ; current handle. The address is assumed to be word-aligned,
60 STMFD R13!,{R0-R5,R14} ;Save some registers
61 MOV R5,R0 ;Look after the address
62 LDR R12,brkpt__wSpace ;Find my workspace address
64 ; --- Check for an exisiting break point ---
66 BL brkpt__findBlock ;Try to find it
67 ADRCS R0,brkpt__exists ;Already one there?
68 BCS %90brkpt_set ;Yes -- return with error
70 ; --- Allocate the breakpoint block ---
72 MOV R0,#6 ;Allocate from the RMA
73 MOV R3,#brkpt__size ;Get the size of the block
74 SWI XOS_Module ;Allocate the block nicely
75 BVS %90brkpt_set ;If it failed, return error
77 ; --- Fill in the breakpoint block ---
79 LDR R0,brkpt__current ;Load the current handle
80 ADR R14,brkpt__table ;Point to the main table
81 LDR R1,[R14,R0,LSL #2] ;Load the correct list head
82 STR R1,[R2,#brkpt__next] ;Store in the breakpoint blk
83 STR R2,[R14,R0,LSL #2] ;And fill in the head again
84 STR R5,[R2,#brkpt__address] ;Save the address there too
85 LDR R1,[R5,#0] ;Load the old contents
86 STR R1,[R2,#brkpt__old] ;Store this away for later
88 ; --- Build the breakpoint entry code ---
90 ADR R14,brkpt__entry ;Point to the basic entry
91 LDMIA R14,{R0,R1} ;Load them into registers
92 ADR R3,brkpt__handler ;Point to the main handler
93 ADD R14,R2,#brkpt__code+16 ;Find the branch instruction
94 SUB R3,R3,R14 ;Subtract the offset
95 MOV R3,R3,LSR #2 ;Shift right two places
96 BIC R3,R3,#&FF000000 ;Clear the opcode byte
97 ORR R3,R3,#&EA000000 ;Make it a branch instruction
98 ADD R14,R2,#brkpt__code ;Point to the actual code
99 STMIA R14,{R0,R1,R3} ;Build the code nicely
101 ; --- Now insert the breakpoint ---
103 SUB R0,R2,R5 ;Find offset from code to blk
104 ADD R0,R0,#brkpt__code-8 ;Find the code, handle pipe
105 MOV R0,R0,LSR #2 ;Shift right two places
106 BIC R0,R0,#&FF000000 ;Clear the opcode byte
107 ORR R0,R0,#&EA000000 ;Make it a branch instruction
108 STR R0,[R5,#0] ;Store it away nicely
109 LDMFD R13!,{R0-R5,R14} ;Unstack registers
110 BICS PC,R14,#V_flag ;And return no errors
112 brkpt__entry STR R14,{PC}-brkpt__code+brkpt__R14
113 ADR R14,{PC}-brkpt__code-4
115 ; --- It went amiss ---
117 90brkpt_set ADD R13,R13,#4 ;Don't restore R0 on exit
118 LDMFD R13!,{R1-R5,R14} ;Unstack registers
119 ORRS PC,R14,#V_flag ;And return the error
122 DCB "There is already a breakpoint at this address",0
126 ; --- brkpt__setViaStar ---
128 ; On entry: R0 == Pointer to command tail
129 ; R1 == number of parameters
133 ; Use: Sets a break point at the desired address. This call
134 ; is made via a * command
136 brkpt__setViaStar ROUT
138 STMFD R13!,{R0-R2,R14} ;Save some registers
139 MOV R1,R0 ;Point to the string
140 MOV R0,#16 ;Default base to read
141 SWI XOS_ReadUnsigned ;Read the address
142 BVS %90brkpt__setViaStar ;Barf on error
143 MOV R0,R2 ;Put address in R0
144 BL brkpt_set ;Set the breakpoint
145 LDMVCFD R13!,{R0-R2,PC}^ ;Return if no error
147 90 ADD R13,R13,#4 ;Skip over R0
148 LDMFD R13!,{R1-R2,R14} ;Get the registers back
149 ORRS PC,R14,#V_flag ;And return with error
153 brkpt__setHelp DCB "*SB sets up a Sledgehammer "
154 DCB "breakpoint at the given address.",13
155 brkpt__setSyn DCB "Syntax: *SB <address>",0
157 ; --- brkpt__handler ---
159 ; On entry: R14 == pointer to the breakpint block
163 ; Use: Called by a breakpoint block, to stop execution
165 brkpt__handler STR R12,brkpt__tmp ;Save R12 -- we need it
166 LDR R12,brkpt__wSpace ;Load my workspace address
167 ADR R12,brkpt__regs ;Find the register save block
168 STMIA R12,{R0-R11} ;Save most of his registers
169 STR R13,[R12,#13*4] ;Also save his R13
170 LDR R0,[R14,#brkpt__R14] ;Find the R14 the bp saved
171 STR R0,[R12,#14*4] ;Write it to the reg block
172 LDR R0,brkpt__tmp ;Get the R12 I saved earlier
173 STR R0,[R12,#12*4] ;Write that to the reg block
174 MOV R0,PC ;Get the PC value
175 AND R0,R0,#&FC000003 ;Extract the flags
176 LDR R1,[R14,#brkpt__address] ;Find the bp's address
177 ORR R0,R0,R1 ;Mix 'em to find his PC
178 STR R0,[R12,#15*4] ;Store as his R15
185 ; --- brkpt__hbHandler ---
191 ; Use: Stops execution after a SWI Sledgehammer_BreakPoint.
193 brkpt__hbHandler ROUT
195 STR R12,brkpt__tmp ;Save R12 -- we need it
196 LDR R12,brkpt__wSpace ;Load my workspace address
197 ADR R12,brkpt__regs ;Find the register save block
198 STMIA R12,{R0-R11} ;Save most of his registers
199 STR R13,[R12,#13*4] ;Also save his R13
200 STR R14,[R12,#14*4] ;And his R14
201 LDR R0,brkpt__tmp ;Get the R12 I saved earlier
202 STR R0,[R12,#12*4] ;Write that to the reg block
209 ; --- brkpt_hardBreak ---
211 ; On entry: [R13+4] == return address to stomp on
215 ; Use: Sets an immediate break specified by a SWI call.
217 EXPORT brkpt_hardBreak
220 MOV R11,R13 ;Keep stack pointer save
221 LDR R12,brkpt__wSpace ;Find my workspace address
222 LDR R10,[R11,#4] ;Load the return address
223 ADR R12,brkpt__regs ;Point to the regs buffer
224 STR R10,[R12,#15*4] ;And as the PC value
225 AND R10,R10,#&FC000003 ;Get his processor flags
226 ADR R12,brkpt__hbHandler ;Point to handler routine
227 ORR R10,R10,R12 ;Mix them up nicely
228 STR R10,[R11,#4] ;Save over return address
229 MOVS PC,R14 ;And return normally
233 ; --- brkpt__findBlock ---
235 ; On entry: R0 == address of breakpoint
237 ; On exit: CS and R0 == address of breakpoint block
238 ; R1 == address of previous next pointer
239 ; CC and R1 corrupted otherwise
241 ; Use: A little obvious, I feel!
243 brkpt__findBlock ROUT
245 STMFD R13!,{R2-R5,R12} ;Stack some registers
246 LDR R12,brkpt__wSpace ;Locate my workspace
247 MOV R5,#brkpt__handles ;A counter thing
248 ADR R4,brkpt__table ;Point to the table
249 MOV R3,R0 ;Remember this value
251 ; --- The main loop ---
253 00 LDR R0,[R4],#4 ;Load the list head
254 SUB R1,R4,#4 ;Get address of previous next
255 CMP R0,#0 ;Is this the end?
256 BEQ %20brkpt__findBlock ;Yes -- skip onwards then
258 10 LDR R2,[R0,#brkpt__address] ;And find its address
259 CMP R2,R3 ;Are these values the same
260 LDMEQFD R13!,{R2-R5,R12} ;Load back my registers
261 ORREQS PC,R14,#C_flag ;Return with C set
263 ADD R1,R0,#brkpt__next ;This is now prev next addr
264 LDR R0,[R0,#brkpt__next] ;Load the next pointer
265 CMP R0,#0 ;Have we finished yet?
266 BNE %10brkpt__findBlock ;No -- keep looking
268 20 SUBS R5,R5,#1 ;Decrement the counter
269 BGT %00brkpt__findBlock ;If more to do, loop
271 MOV R0,R3 ;Put R0 back again
272 LDMFD R13!,{R2-R5,R12} ;Load back my registers
273 BICS PC,R14,#C_flag ;Return with C clear
277 ; --- brkpt_translate ---
279 ; On entry: R0 == address to translate
281 ; On exit: R0 == the address we are really interested in
283 ; Use: Returns the address given, as if there was no breakpoint
286 EXPORT brkpt_translate
289 STMFD R13!,{R1,R14} ;Stack registers
290 BL brkpt__findBlock ;Find the block
291 ADDCS R0,R0,#brkpt__old ;Found it -- add happily
292 LDMFD R13!,{R1,PC}^ ;Return to caller
296 ; --- brkpt_remove ---
298 ; On entry: R0 == address of breakpoint
302 ; Use: Removes the break point (if any) at the given address
307 STMFD R13!,{R0-R2,R14} ;Stack registers
308 BL brkpt__findBlock ;Find the block
309 BCC %99brkpt_remove ;Found it -- add happily
311 LDR R14,[R0,#brkpt__next] ;Load the next pointer
312 STR R14,[R1,#0] ;Store over previous addr
313 LDR R14,[R0,#brkpt__old] ;Get the old value out
314 LDR R2,[R0,#brkpt__address] ;And find its address
315 STR R14,[R2,#0] ;Store the value back
316 MOV R2,R0 ;Point to block in R2
317 MOV R0,#7 ;Free the block
318 SWI XOS_Module ;Yes siree bob matey
320 99brkpt_remove LDMFD R13!,{R0-R2,PC}^ ;Return to caller
324 ; --- brkpt_remAll ---
330 ; Use: Removes all the breakpoints currently installed.
335 STMFD R13!,{R0-R5,R12,R14} ;Save some registers
336 LDR R12,brkpt__wSpace ;Find my workspace address
337 MOV R5,#brkpt__handles ;A counter thing
338 ADR R4,brkpt__table ;Point to the table
340 ; --- The main loop ---
342 00brkpt_remAll LDR R2,[R4],#4 ;Load the list head
343 CMP R2,#0 ;Is this the end?
344 BEQ %20brkpt_remAll ;Yes -- skip onwards then
345 05brkpt_remAll LDR R14,[R2,#brkpt__old] ;Get the old value out
346 LDR R0,[R2,#brkpt__address] ;And find its address
347 STR R14,[R0,#0] ;Store the value back
348 LDR R3,[R2,#brkpt__next] ;Load the next pointer
349 MOV R0,#7 ;Free the RMA block
350 SWI XOS_Module ;Yes, really do it
351 MOVS R2,R3 ;Move on to the next one
352 BNE %05brkpt_remAll ;If more to do, loop
354 20brkpt_remAll MOV R14,#0 ;Zero the breakpoint list hdr
355 STR R14,[R4,#-4] ;Store over the list head
356 SUBS R5,R5,#1 ;Decrement the counter
357 BGT %00brkpt_remAll ;If more to do, loop
359 LDMFD R13!,{R0-R5,R12,PC}^ ;Return to caller
363 ; --- brkpt__remViaStar ---
365 ; On entry: R0 == Pointer to command tail
366 ; R1 == number of parameters
370 ; Use: Removes the break point at the given address. This call
371 ; is made via a * command
373 brkpt__remViaStar ROUT
375 CMP R1,#0 ;Has he ommitted the args?
376 BEQ %50brkpt__remViaStar ;Yes -- maybe we get 'em all
377 LDRB R2,[R0,#0] ;Get the first character
378 CMP R2,#'Y' ;Is it a 'Y'?
379 CMPNE R2,#'y' ;Check both cases
380 BEQ brkpt_remAll ;Yes -- remove all then
381 STMFD R13!,{R0-R2,R14} ;Save some registers
382 MOV R1,R0 ;Point to the string
383 MOV R0,#16 ;Default base to read
384 SWI XOS_ReadUnsigned ;Read the address
385 BVS %90brkpt__remViaStar ;Barf on error
386 MOV R0,R2 ;Put address in R0
387 BL brkpt_remove ;Set the breakpoint
388 LDMVCFD R13!,{R0-R2,PC}^ ;Return if no error
390 90 ADD R13,R13,#4 ;Skip over R0
391 LDMFD R13!,{R1-R2,R14} ;Get the registers back
392 ORRS PC,R14,#V_flag ;And return with error
394 ; --- Maybe remove all breakpoints ---
396 50 STMFD R13!,{R0,R14} ;Save some registers
397 ADR R0,brkpt__rmConf ;Point to confirm message
398 BL hammer_confirm ;Are we sure about this?
399 BLCS brkpt_remAll ;Yes -- do it then
400 LDMFD R13!,{R0,PC}^ ;Return to caller
402 brkpt__rmConf DCB "Remove all breakpoints?",0
406 brkpt__remHelp DCB "*RB removes any Sledgehammer "
407 DCB "breakpoint set at that address. If the address "
408 DCB "is omitted, all breakpoints are removed.",13
409 brkpt__remSyn DCB "Syntax: *RB [<address>]",0
411 ; --- brkpt_exist ---
413 ; On entry: R0 == address to test for
415 ; On exit: CC if there is no breakpoint here
418 ; Use: Informs the user if there is a breakpint at the address
424 STMFD R13!,{R0,R1,R14} ;Stack some registers
425 BL brkpt__findBlock ;Find the block thingy
426 LDMFD R13!,{R0,R1,PC} ;Return all happy
428 ; --- brkpt__init ---
434 ; Use: Initialises the breakpoint manager.
438 STMFD R13!,{R0-R9,R14} ;Save a load of registers
439 MOV R0,#bpFlag__inited
449 STMIA R12,{R0-R9} ;Fill the workspace
450 LDMFD R13!,{R0-R9,PC}^ ;Return to caller
460 ; Use: Tidies away all installed breakpoints.
464 B brkpt_remAll ;Remove all the breakpoints
470 ;----- Constants ------------------------------------------------------------
474 ;----- Data structures ------------------------------------------------------
477 brkpt__next # 4 ;Link to next breakpoint
478 brkpt__address # 4 ;Where the breakpoint `is'
479 brkpt__old # 4 ;The previous value
480 brkpt__R14 # 4 ;User's R14 value on entry
481 brkpt__code # 12 ;The breakpoint entry code
482 brkpt__size # 0 ;Size of a breakpoint block
484 ;----- Workspace ------------------------------------------------------------
489 brkpt__flags # 4 ;Various flags
490 brkpt__current # 4 ;Current breakpoint handle
491 brkpt__table # brkpt__handles*4 ;The links for the bp lists
493 brkpt__regs # 16*4 ;Register block for brkpt
495 brkpt__wSize EQU {VAR}-brkpt__wStart
497 bpFlag__inited EQU (1<<0)
499 AREA |Quartz$$Table|,CODE,READONLY
506 AREA |Quartz$$Commands|,CODE,READONLY
509 DCD brkpt__setViaStar
515 DCD brkpt__remViaStar
520 ;----- That's all, folks ----------------------------------------------------