Initial revision
[ssr] / StraySrc / Hammer / s / driver
1 ;
2 ; driver.s
3 ;
4 ; The text-only interface to Sledgehammer (TMA)
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 ;----- Standard header ------------------------------------------------------
28
29 GET libs:header
30 GET libs:swis
31
32 GET libs:stream
33
34 ;----- External dependencies ------------------------------------------------
35
36 GET quartz:string
37
38 GET sh.brkpt
39 GET sh.armEmul
40 GET sh.asm
41 GET sh.diss
42 GET sh.hammer
43
44 ;----- Main code ------------------------------------------------------------
45
46 AREA |Hammer$$Code|,CODE,READONLY
47
48 ; --- driver ---
49 ;
50 ; On entry: R0 == pointer to a register block
51 ;
52 ; On exit: Doesn't
53 ;
54 ; Use: Text only interactive debugger interface
55
56 EXPORT driver
57 driver ROUT
58
59 BL hammer_getStack ;Get our own pretty stack
60 MOV R3,R0 ;Preserve block pointer
61 MOV R10,R13 ;Remember stack base address
62 MOV R14,PC ;Get PC with flags
63 TST R14,#3 ;Are we in user mode?
64 LDRNE R13,[R3,#13*4] ;No -- use his stack pointer
65
66 driver__next LDR R0,[R3,#15*4] ;Get the 'PC'
67 BIC R0,R0,#&FC000003 ;Clear flags
68 BL diss_address ;Set this as the diss address
69 BL brkpt_translate ;Translate the address
70 LDR R0,[R0,#0] ;Load the instruction
71 BL diss_disassemble ;Disassemble the instruction
72 SWI XOS_NewLine ;Print a newline
73 SWI XOS_Write0 ;Print it out nicely
74 SWI XOS_NewLine ;Print a newline
75
76 10driver SWI XOS_WriteS ;Print out the following
77 DCB 10,"Sledgehammer [stwx rad bke nzcv *oh]",0
78
79 MOV R0,#229 ;Set escape action
80 MOV R1,#1 ;Just generate key code
81 MOV R2,#0 ;Set the state
82 SWI XOS_Byte ;Do it
83
84 15driver SWI XOS_ReadC ;Read a character
85 CMP R0,#27 ;Was it escape?
86 MOVEQ R0,#'t' ;Yes -- make it continue
87 CMP R0,#32 ;How about space
88 MOVEQ R0,#'s' ;Yeap -- make it step
89 ORR R0,R0,#&20 ;Make it lower case
90 ADR R2,driver__table ;Point to the table
91 20driver LDR R4,[R2],#8 ;Load the byte
92 CMP R4,#0 ;Was there one?
93 BEQ %15driver ;Nope -- keep trying
94 CMP R4,R0 ;Was this what he typed?
95 BNE %20driver ;No -- keep on trying
96 SWI XOS_WriteI+32 ;Print a space
97 SWI XOS_WriteC ;Print out the character
98 SWI XOS_NewLine ;Let's be pretty about this
99 SWI XOS_NewLine
100 SUB PC,R2,#4 ;Do the instruction
101
102 driver__table DCD 's'
103 B driver__step
104 DCD 't'
105 B driver__cont
106 DCD 'w'
107 B driver__soft
108 DCD 'x'
109 SWI OS_BreakPt
110 DCD 'r'
111 B driver__regDump
112 DCD 'a'
113 B driver__next;driver__alter
114 DCD 'd'
115 B driver__diss
116 DCD 'b'
117 B driver__break
118 DCD 'k'
119 B driver__killBrk
120 DCD 'e'
121 B driver__killAll
122 DCD 'n'
123 B driver__toggleN
124 DCD 'z'
125 B driver__toggleZ
126 DCD 'c'
127 B driver__toggleC
128 DCD 'v'
129 B driver__toggleV
130 DCD '*'
131 B driver__oscli
132 DCD 'o'
133 B driver__next;driver__options
134 DCD 'h'
135 B driver__help
136 DCD 0
137
138 ; --- Single Step ---
139
140 driver__step MOV R0,#229 ;Set escape action
141 MOV R2,#0 ;Set the state to what it was
142 SWI XOS_Byte ;Do it
143
144 MOV R13,R10 ;Use our private stack
145 MOV R0,R3 ;Point to register block
146 BL armEmul ;Emulate an instruction
147 MOV R14,PC ;Get PC with flags
148 TST R14,#3 ;Are we in user mode?
149 LDRNE R13,[R3,#13*4] ;No -- use his stack pointer
150 B driver__next ;Do the next one
151
152 ; --- Continue ---
153
154 driver__cont MOV R0,#229 ;Set escape action
155 MOV R2,#0 ;Set the state to what it was
156 SWI XOS_Byte ;Do it
157
158 LDR R0,[R3,#15*4] ;Get the current PC
159 BIC R0,R0,#&FC000003 ;Get rid of flags
160 BL brkpt_exist ;Is there a breakpoint here?
161 LDMCCIA R3,{R0-PC}^ ;No -- continue his execution
162
163 MOV R13,R10 ;Use our private stack
164 MOV R0,R3 ;Point to register block
165 BL armEmul ;Emulate an instruction
166 LDMIA R3,{R0-PC}^ ;Continue pleasently
167
168 ; --- Soft emulation ---
169
170 driver__soft ROUT
171
172 MOV R0,#229 ;Set escape action
173 MOV R2,#0 ;Set the state to what it was
174 SWI XOS_Byte ;Do it
175
176 MOV R13,R10 ;Yes -- Use our private stack
177 00driver__soft MOV R0,R3 ;...point to register block
178 BL armEmul ;...emulate an instruction
179 LDR R0,[R3,#15*4] ;Get the current PC
180 BIC R0,R0,#&FC000003 ;Get rid of flags
181 BL brkpt_exist ;Is there a breakpoint here?
182 BCC %00driver__soft ;No -- keep looping
183 MOV R14,PC ;Get PC with flags
184 TST R14,#3 ;Are we in user mode?
185 LDRNE R13,[R3,#13*4] ;No -- use his stack pointer
186 B driver__next ;And tell user about it
187
188 LTORG
189
190 ; --- Help display ---
191
192 driver__help ADR R0,driver__helpText ;Point to my help text
193 SWI XOS_PrettyPrint ;Display it on the screen
194 B driver__next ;Rejoin the main loop
195
196 driver__helpText
197 DCB "Commands available:",13
198 DCB 13
199 DCB "[S]ingle step (also SPACE)",13
200 DCB "con[T]inue (also ESCAPE)",13
201 DCB "[W]hisper mode",13
202 DCB "e[X]it application",13
203 DCB "[R]egister list",13
204 DCB "[A]lter register value",13
205 DCB "[D]isassemble around current PC",13
206 DCB "[B]reakpoint set",13
207 DCB "[K]ill breakpoint",13
208 DCB "toggle [N,Z,C,V] flag",13
209 DCB "[E]xterminate all breakpoints",13
210 DCB "[*] commands",13
211 DCB "[O]ptions",13
212 DCB "[H]elp",13
213 DCB 0
214
215 ; --- Set a breakpoint ---
216
217 driver__break BL driver__readAddr ;Read the address he typed
218 BVS driver__error ;If he spasmed, return
219 BLCS brkpt_set ;Try to set the breakpoint
220 BVS driver__error ;If he spasmed, return
221 B driver__next ;And rejoin the main loop
222
223 ; --- Remove a breakpoint ---
224
225 driver__killBrk BL driver__readAddr ;Read the address he typed
226 BVS driver__error ;If he spasmed, return
227 BLCS brkpt_remove ;Try to set the breakpoint
228 BVS driver__error ;If he spasmed, return
229 B driver__next ;And rejoin the main loop
230
231 ; --- Remove all breakpoints ---
232
233 driver__killAll ADR R0,driver__kaMsg ;Point to message string
234 BL hammer_confirm ;Get confirmation on this
235 BLCS brkpt_remAll ;If OK, remove all of them
236 B driver__next ;And rejoin the main loop
237
238 driver__kaMsg DCB "Remove all breakpoints?",0
239
240 driver__error ADD R0,R0,#4 ;Point to the error
241 SWI XOS_Write0 ;Display the message
242 SWI XOS_NewLine ;Move to new line
243 B driver__next ;And rejoin the main loop
244
245 ; --- * commands ---
246
247 driver__oscli ROUT
248
249 STMFD R13!,{R0-R5} ;Save some registers
250 BL str_buffer ;Get me a nice buffer
251 MOV R5,R1 ;Look after the buffer
252
253 00driver__oscli SWI XOS_WriteS ;Write a prompt string
254 DCB "Sledgehammer *",0
255 MOV R0,R5 ;Point to it nicely
256 MOV R1,#256 ;Give the buffer size
257 MOV R2,#32 ;Allow all printable chars
258 MOV R3,#255
259 SWI XOS_ReadLine ;Read a command line
260 BVS %10driver__oscli ;Failed -- report error
261 LDRB R1,[R5,#0] ;Load the first character
262 CMP R1,#13 ;Is the string empty?
263 BEQ %20driver__oscli ;Yes -- return then
264 MOV R0,R5 ;Point to the buffer
265 SWI XOS_CLI ;Do the command nicely
266 BVS %10driver__oscli ;Failed -- report error
267 B %00driver__oscli ;Go round for some more
268
269 10driver__oscli ADD R0,R0,#4 ;Point to error message
270 SWI XOS_Write0 ;Display it
271 B %00driver__oscli ;Go round for some more
272
273 20driver__oscli LDMFD R13!,{R0-R5} ;Unstack registers
274 B driver__next ;And rejoin the main loop
275
276 ; --- Toggle flags ---
277
278 driver__toggleN MOV R4,#N_flag ;Get the flag bit
279 MOV R5,#'N' ;And the name
280 B driver__toggle ;Do the toggle op
281
282 driver__toggleZ MOV R4,#Z_flag ;Get the flag bit
283 MOV R5,#'Z' ;And the name
284 B driver__toggle ;Do the toggle op
285
286 driver__toggleC MOV R4,#C_flag ;Get the flag bit
287 MOV R5,#'C' ;And the name
288 B driver__toggle ;Do the toggle op
289
290 driver__toggleV MOV R4,#V_flag ;Get the flag bit
291 MOV R5,#'V' ;And the name
292 B driver__toggle ;Do the toggle op
293
294 driver__toggle LDR R14,[R3,#15*4] ;Load current flags
295 EOR R14,R14,R4 ;Toggle the flag
296 STR R14,[R3,#15*4] ;Save them back again
297 TST R14,R4 ;Is it on or off now?
298 MOV R0,R5 ;Get the flag's name
299 SWI XOS_WriteC ;Display it
300 SWI XOS_WriteS ;Display some text
301 DCB " flag now ",0
302 ADREQ R0,driver__flagOff ;Point to the right string
303 ADRNE R0,driver__flagOn ;Whichever one that is
304 SWI XOS_Write0 ;And display it
305 SWI XOS_NewLine ;Follow with a newline
306 B driver__next ;And rejoin main loop
307
308 driver__flagOff DCB "off.",0
309 driver__flagOn DCB "on.",0
310
311 ; --- Disassemble context ---
312
313 driver__diss ROUT
314
315 LDR R4,[R3,#15*4] ;Load current program count
316 BIC R4,R4,#&FC000003 ;Clear PSR flags
317
318 BL driver__readAddr ;Get an address to display
319 BVS driver__error ;If he goofed, report error
320 MOVCC R0,R4 ;If none, use the PC
321
322 SUB R5,R0,#40 ;Do 10 instrs each side
323 MOV R6,#21 ;That's 21 instructions total
324
325 MOV R0,R5 ;Get the disassembly base
326 BL diss_address ;Set disassembly up nicely
327
328 00driver__diss MOV R0,R5 ;Get the disassembly address
329 BL brkpt_exist ;Is there a breakpoint there?
330 SWICS XOS_WriteI+"*" ;Yes -- put a splodge there
331 SWICC XOS_WriteI+" " ;Otherwise leave a gap
332 CMP R0,R4 ;Is this the current one?
333 SWIEQ XOS_WriteI+">" ;Yes -- mark it somehow
334 SWINE XOS_WriteI+" " ;Otherwise leave a space
335 SWI XOS_WriteI+" " ;Gap before disassembly
336
337 BL brkpt_translate ;Translate the address
338 LDR R0,[R0,#0] ;Load the instruction
339 BL diss_disassemble ;Disassemble it
340 SWI XOS_Write0 ;Display the result
341 SWI XOS_NewLine ;And move down a line
342
343 SUBS R6,R6,#1 ;Decrement the counter
344 ADDGE R5,R5,#4 ;If more to go, bump address
345 BGE %00driver__diss ;And go round again
346
347 B driver__next ;Rejoin the main loop
348
349 LTORG
350
351 ; --- Register dump ---
352
353 driver__regDump ROUT
354
355 STMFD R13!,{R0-R12} ;Save some registers
356 MOV R0,#229 ;Set escape action
357 MOV R2,#0 ;Set the state to what it was
358 SWI XOS_Byte ;Do it
359
360 ; --- Start the main display loop ---
361
362 MOV R12,R3 ;Keep pointer to dump block
363 ADR R11,driver__regNames ;Point to register name tbl
364 MOV R10,#0 ;Which register we're on
365
366 ; --- Display a register ---
367
368 00 ADD R0,R11,R10,LSL #2 ;Point to the string
369 SWI OS_Write0 ;Display register name
370 SWI OS_WriteS ;Display immediate string
371 DCB " == &",0 ;A separater string
372 LDR R0,[R12,R10,LSL #2] ;Load the register value
373 BL driver__writeHex ;Display register value
374 SWI OS_WriteS ;Display more immediate
375 DCB " ",0 ;Just some spaces
376 ADD R10,R10,#1 ;Increment register count
377 TST R10,#3 ;Now a multiple of 4?
378 SWIEQ OS_NewLine ;Yes -- new line then
379 CMP R10,#16 ;Finished all registers?
380 BLT %00driver__regDump ;No -- do some more then
381
382 ; --- Now display R14 and R15 with PSR bits testually ---
383
384 SWI OS_NewLine ;Another newline
385 SWI OS_WriteS ;Display immediate stuff
386 DCB "R14 == &",0
387 LDR R9,[R12,#14*4] ;Load the R14 value
388 BL driver__psr ;Display all the PSR bits
389 SWI OS_NewLine ;Another newline
390 SWI OS_WriteS ;Display immediate stuff
391 DCB " PC == &",0
392 LDR R9,[R12,#15*4] ;Load the PC value
393 BL driver__psr ;Display all the PSR bits
394 SWI OS_NewLine ;Another newline
395 SWI OS_NewLine ;And one more for luck
396 LDMFD R13!,{R0-R12} ;Get register back
397 B driver__next ;Get the next command
398
399 LTORG
400
401 driver__regNames
402 DCB " R0",0
403 DCB " R1",0
404 DCB " R2",0
405 DCB " R3",0
406 DCB " R4",0
407 DCB " R5",0
408 DCB " R6",0
409 DCB " R7",0
410 DCB " R8",0
411 DCB " R9",0
412 DCB "R10",0
413 DCB "R11",0
414 DCB "R12",0
415 DCB "R13",0
416 DCB "R14",0
417 DCB " PC",0
418
419 ; --- driver__psr ---
420 ;
421 ; On entry: R9 == value to display
422 ;
423 ; On exit: R0-R12 corrupted, maybe
424 ;
425 ; Use: Displays R9 with PSR bits stripped away, and then with
426 ; all the PSR bits described too.
427
428 driver__psr ROUT
429
430 STMFD R13!,{R14} ;Save the link register
431 BIC R0,R9,#&FC000003 ;Get the PC bits only
432 BL driver__writeHex ;Display them in hex
433
434 SWI OS_WriteS ;Some more spaces
435 DCB ", flags == ",0
436 MOV R0,#'N' ;First do the `N' flag
437 TST R9,#N_flag ;Is it set
438 ORREQ R0,R0,#&20 ;No -- force to lower case
439 SWI OS_WriteC ;Display the character
440 MOV R0,#'Z' ;First do the `N' flag
441 TST R9,#Z_flag ;Is it set
442 ORREQ R0,R0,#&20 ;No -- force to lower case
443 SWI OS_WriteC ;Display the character
444 MOV R0,#'C' ;First do the `N' flag
445 TST R9,#C_flag ;Is it set
446 ORREQ R0,R0,#&20 ;No -- force to lower case
447 SWI OS_WriteC ;Display the character
448 MOV R0,#'V' ;First do the `N' flag
449 TST R9,#V_flag ;Is it set
450 ORREQ R0,R0,#&20 ;No -- force to lower case
451 SWI OS_WriteC ;Display the character
452
453 SWI OS_WriteS ;Yet more stuff
454 DCB ", mode == ",0
455 ADR R0,driver__modes ;Point to the mode strings
456 AND R14,R9,#3 ;Get the mode bits
457 ADD R0,R0,R14,LSL #2 ;Point to the correct string
458 SWI OS_Write0 ;Display the mode setting
459
460 TST R9,#IRQ_disable ;Is the IRQ bit on or off?
461 ADREQ R0,driver__irqOn ;If off, point to message
462 SWIEQ OS_Write0 ;And display the string
463 TST R9,#FIQ_disable ;Is the FIQ bit on or off?
464 ADREQ R0,driver__fiqOn ;If off, point to message
465 SWIEQ OS_Write0 ;And display the string
466 LDMFD R13!,{PC}^ ;Return to caller
467
468 LTORG
469
470 driver__modes DCB "USR",0
471 DCB "FIQ",0
472 DCB "IRQ",0
473 DCB "SVC",0
474
475 driver__irqOn DCB ", IRQ",0
476 driver__fiqOn DCB ", FIQ",0
477
478 driver__writeHex ROUT
479
480 STMFD R13!,{R0-R2,R14}
481 SUB R13,R13,#16
482 MOV R1,R13
483 MOV R2,#16
484 SWI OS_ConvertHex8
485 SWI OS_Write0
486 ADD R13,R13,#16
487 LDMFD R13!,{R0-R2,PC}^
488
489 LTORG
490
491 ; --- driver__readAddr ---
492 ;
493 ; On entry: --
494 ;
495 ; On exit: Error, or CC for no entry, or R0 == address
496 ;
497 ; Use: Interprets an address as typed by the user.
498
499 driver__readAddr ROUT
500
501 BIC R14,R14,#V_flag ;Assume all is well
502 STMFD R13!,{R1-R5,R8,R14} ;Save some registers
503 SWI XOS_WriteS ;Display the prompt
504 DCB "([<reg>] [+|- <offset>]) | <address> :",0
505 SUB R13,R13,#20 ;Make a small buffer
506 MOV R5,R3 ;Look after register block
507 MOV R0,R13 ;Point to my buffer
508 MOV R1,#20 ;Give it the buffer size
509 MOV R2,#32 ;Minimum value to allow
510 MOV R3,#255 ;Allow all printable chars
511 SWI XOS_ReadLine ;Read the line then
512 BVS %90driver__readAddr ;If he messed up, report err
513 MOV R3,R5 ;Restore register block ptr
514
515 MOV R8,R13 ;Point to the string
516 MOV R5,#0 ;Initial address offset
517 MOV R4,#0 ;Clear some flags
518 BL asm_register ;Try to read a register name
519 LDRVC R5,[R3,R0,LSL #2] ;If OK get register value
520 BICVC R5,R5,#&FC000003 ;And clear possible PSR flags
521 ORRVC R4,R4,#3 ;We have reg/We read sthing
522
523 00 LDRB R14,[R8],#1 ;Load a byte from the string
524 CMP R14,#' ' ;Is it a space
525 BEQ %00driver__readAddr ;Yes -- go for another
526
527 CMP R14,#32 ;Is this the string end?
528 BLO %10driver__readAddr ;Yes -- weird things happened
529 CMP R14,#'-' ;Is it a '-'?
530 ORREQ R4,R4,#4 ;Yes -- subtract offset then
531 CMPNE R14,#'+' ;Or a '+'?
532 ORREQ R4,R4,#1 ;This is something typed
533 BNE %05driver__readAddr ;No -- skip
534
535 TST R4,#2 ;Do we have a base reg?
536 LDREQ R5,[R3,#15*4] ;No -- use the PC then
537 BICEQ R5,R5,#&FC000003 ;And clear possible PSR flags
538
539 MOV R1,R8 ;Point to the string
540 MOV R0,#10 ;Expect a decimal number
541 SWI XOS_ReadUnsigned ;Try to understand the value
542 BVS %90driver__readAddr ;If failed, report error
543 TST R4,#4 ;Was it a subtract?
544 SUBNE R5,R5,R2 ;Yes -- subtract offset
545 ADDEQ R5,R5,R2 ;Otherwise add it
546 B %10driver__readAddr ;And branch ahead
547
548 05 TST R4,#2 ;Was there a register?
549 BNE %10driver__readAddr ;Yes -- almost done then
550
551 SUB R1,R8,#1 ;Point to the string
552 MOV R0,#16 ;Expect a hex number
553 SWI XOS_ReadUnsigned ;Try to understand the value
554 BVS %90driver__readAddr ;If failed, report error
555 MOV R5,R2 ;Get the address he typed
556 ORR R4,R4,#1 ;He typed something
557
558 10 TST R4,#1 ;Was there anything at all?
559 BEQ %80driver__readAddr ;No -- return C clear then
560
561 BIC R0,R5,#3 ;Truncate to word boundary
562 ADD R13,R13,#20 ;Restore the stack
563 LDMFD R13!,{R1-R5,R8,R14} ;Unstack registers
564 ORRS PC,R14,#C_flag ;And return with C proudly on
565
566 ; --- Lazy user typed nothing ---
567
568 80 ADD R13,R13,#20 ;Restore the stack
569 LDMFD R13!,{R1-R5,R8,R14} ;Unstack registers
570 BICS PC,R14,#C_flag ;And return with C sadly off
571
572 ; --- Stupid user caused an error ---
573
574 90 ADD R13,R13,#20 ;Restore the stack
575 LDMFD R13!,{R1-R5,R8,R14} ;Unstack registers
576 ORRS PC,R14,#V_flag ;So set V on exit
577
578 LTORG
579
580 ;----- That's all, folks ----------------------------------------------------
581
582 END