Initial revision
[ssr] / StraySrc / Hammer / s / brkpt
1 ;
2 ; brkpt.s
3 ;
4 ; Breakpoint handling (MDW)
5 ;
6 ; © 1994-1998 Straylight
7 ;
8
9 ;----- Licensing note -------------------------------------------------------
10 ;
11 ; This file is part of Straylight's Sledgehammer debugger.
12 ;
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)
16 ; any later version.
17 ;
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.
22 ;
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.
26
27 ;----- Things not to forget -------------------------------------------------
28 ;
29 ; When removing a break point, ensure instruction is still our branch
30
31 ;----- Standard header ------------------------------------------------------
32
33 GET libs:header
34 GET libs:swis
35 GET libs:stream
36
37 ;----- External dependencies ------------------------------------------------
38
39 GET sh.armEmul
40 GET sh.driver
41 GET sh.hammer
42
43 ;----- Main code ------------------------------------------------------------
44
45 AREA |Hammer$$Code|,CODE,READONLY
46
47 ; --- brkpt_set ---
48 ;
49 ; On entry: R0 == address to set breakpoint
50 ;
51 ; On exit: May return error
52 ;
53 ; Use: Sets a breakpoint at the given location, giving it the
54 ; current handle. The address is assumed to be word-aligned,
55 ; and writable.
56
57 EXPORT brkpt_set
58 brkpt_set ROUT
59
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
63
64 ; --- Check for an exisiting break point ---
65
66 BL brkpt__findBlock ;Try to find it
67 ADRCS R0,brkpt__exists ;Already one there?
68 BCS %90brkpt_set ;Yes -- return with error
69
70 ; --- Allocate the breakpoint block ---
71
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
76
77 ; --- Fill in the breakpoint block ---
78
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
87
88 ; --- Build the breakpoint entry code ---
89
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
100
101 ; --- Now insert the breakpoint ---
102
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
111
112 brkpt__entry STR R14,{PC}-brkpt__code+brkpt__R14
113 ADR R14,{PC}-brkpt__code-4
114
115 ; --- It went amiss ---
116
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
120
121 brkpt__exists DCD 1
122 DCB "There is already a breakpoint at this address",0
123
124 LTORG
125
126 ; --- brkpt__setViaStar ---
127 ;
128 ; On entry: R0 == Pointer to command tail
129 ; R1 == number of parameters
130 ;
131 ; On exit: --
132 ;
133 ; Use: Sets a break point at the desired address. This call
134 ; is made via a * command
135
136 brkpt__setViaStar ROUT
137
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
146
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
150
151 LTORG
152
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
156
157 ; --- brkpt__handler ---
158 ;
159 ; On entry: R14 == pointer to the breakpint block
160 ;
161 ; On exit: --
162 ;
163 ; Use: Called by a breakpoint block, to stop execution
164
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
179
180 MOV R0,R12
181 B driver
182
183 brkpt__tmp DCD 4
184
185 ; --- brkpt__hbHandler ---
186 ;
187 ; On entry: --
188 ;
189 ; On exit: --
190 ;
191 ; Use: Stops execution after a SWI Sledgehammer_BreakPoint.
192
193 brkpt__hbHandler ROUT
194
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
203
204 MOV R0,R12
205 B driver
206
207 ROUT
208
209 ; --- brkpt_hardBreak ---
210 ;
211 ; On entry: [R13+4] == return address to stomp on
212 ;
213 ; On exit: --
214 ;
215 ; Use: Sets an immediate break specified by a SWI call.
216
217 EXPORT brkpt_hardBreak
218 brkpt_hardBreak ROUT
219
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
230
231 LTORG
232
233 ; --- brkpt__findBlock ---
234 ;
235 ; On entry: R0 == address of breakpoint
236 ;
237 ; On exit: CS and R0 == address of breakpoint block
238 ; R1 == address of previous next pointer
239 ; CC and R1 corrupted otherwise
240 ;
241 ; Use: A little obvious, I feel!
242
243 brkpt__findBlock ROUT
244
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
250
251 ; --- The main loop ---
252
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
257
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
262
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
267
268 20 SUBS R5,R5,#1 ;Decrement the counter
269 BGT %00brkpt__findBlock ;If more to do, loop
270
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
274
275 LTORG
276
277 ; --- brkpt_translate ---
278 ;
279 ; On entry: R0 == address to translate
280 ;
281 ; On exit: R0 == the address we are really interested in
282 ;
283 ; Use: Returns the address given, as if there was no breakpoint
284 ; there.
285
286 EXPORT brkpt_translate
287 brkpt_translate ROUT
288
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
293
294 LTORG
295
296 ; --- brkpt_remove ---
297 ;
298 ; On entry: R0 == address of breakpoint
299 ;
300 ; On exit: --
301 ;
302 ; Use: Removes the break point (if any) at the given address
303
304 EXPORT brkpt_remove
305 brkpt_remove ROUT
306
307 STMFD R13!,{R0-R2,R14} ;Stack registers
308 BL brkpt__findBlock ;Find the block
309 BCC %99brkpt_remove ;Found it -- add happily
310
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
319
320 99brkpt_remove LDMFD R13!,{R0-R2,PC}^ ;Return to caller
321
322 LTORG
323
324 ; --- brkpt_remAll ---
325 ;
326 ; On entry: --
327 ;
328 ; On exit: --
329 ;
330 ; Use: Removes all the breakpoints currently installed.
331
332 EXPORT brkpt_remAll
333 brkpt_remAll ROUT
334
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
339
340 ; --- The main loop ---
341
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
353
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
358
359 LDMFD R13!,{R0-R5,R12,PC}^ ;Return to caller
360
361 LTORG
362
363 ; --- brkpt__remViaStar ---
364 ;
365 ; On entry: R0 == Pointer to command tail
366 ; R1 == number of parameters
367 ;
368 ; On exit: --
369 ;
370 ; Use: Removes the break point at the given address. This call
371 ; is made via a * command
372
373 brkpt__remViaStar ROUT
374
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
389
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
393
394 ; --- Maybe remove all breakpoints ---
395
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
401
402 brkpt__rmConf DCB "Remove all breakpoints?",0
403
404 LTORG
405
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
410
411 ; --- brkpt_exist ---
412 ;
413 ; On entry: R0 == address to test for
414 ;
415 ; On exit: CC if there is no breakpoint here
416 ; CS otherwise
417 ;
418 ; Use: Informs the user if there is a breakpint at the address
419 ; passed.
420
421 EXPORT brkpt_exist
422 brkpt_exist ROUT
423
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
427
428 ; --- brkpt__init ---
429 ;
430 ; On entry: --
431 ;
432 ; On exit: --
433 ;
434 ; Use: Initialises the breakpoint manager.
435
436 brkpt__init ROUT
437
438 STMFD R13!,{R0-R9,R14} ;Save a load of registers
439 MOV R0,#bpFlag__inited
440 MOV R1,#0
441 MOV R2,#0
442 MOV R3,#0
443 MOV R4,#0
444 MOV R5,#0
445 MOV R6,#0
446 MOV R7,#0
447 MOV R8,#0
448 MOV R9,#0
449 STMIA R12,{R0-R9} ;Fill the workspace
450 LDMFD R13!,{R0-R9,PC}^ ;Return to caller
451
452 LTORG
453
454 ; --- brkpt__die ---
455 ;
456 ; On entry: --
457 ;
458 ; On exit: --
459 ;
460 ; Use: Tidies away all installed breakpoints.
461
462 brkpt__die ROUT
463
464 B brkpt_remAll ;Remove all the breakpoints
465
466 LTORG
467
468 brkpt__wSpace DCD 0
469
470 ;----- Constants ------------------------------------------------------------
471
472 brkpt__handles EQU 8
473
474 ;----- Data structures ------------------------------------------------------
475
476 ^ 0
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
483
484 ;----- Workspace ------------------------------------------------------------
485
486 ^ 0,R12
487 brkpt__wStart # 0
488
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
492
493 brkpt__regs # 16*4 ;Register block for brkpt
494
495 brkpt__wSize EQU {VAR}-brkpt__wStart
496
497 bpFlag__inited EQU (1<<0)
498
499 AREA |Quartz$$Table|,CODE,READONLY
500
501 DCD brkpt__wSize
502 DCD brkpt__wSpace
503 DCD brkpt__init
504 DCD brkpt__die
505
506 AREA |Quartz$$Commands|,CODE,READONLY
507
508 DCB "SB",0
509 DCD brkpt__setViaStar
510 DCD &00010001
511 DCD brkpt__setSyn
512 DCD brkpt__setHelp
513
514 DCB "RB",0
515 DCD brkpt__remViaStar
516 DCD &00010000
517 DCD brkpt__remSyn
518 DCD brkpt__remHelp
519
520 ;----- That's all, folks ----------------------------------------------------
521
522 END