chiark / gitweb /
Create readable text `.bas' for each tokenized BASIC `,ffb' file.
[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