4 ; The text-only interface to Sledgehammer (TMA)
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 ;----- Standard header ------------------------------------------------------
34 ;----- External dependencies ------------------------------------------------
44 ;----- Main code ------------------------------------------------------------
46 AREA |Hammer$$Code|,CODE,READONLY
50 ; On entry: R0 == pointer to a register block
54 ; Use: Text only interactive debugger interface
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
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
76 10driver SWI XOS_WriteS ;Print out the following
77 DCB 10,"Sledgehammer [stwx rad bke nzcv *oh]",0
79 MOV R0,#229 ;Set escape action
80 MOV R1,#1 ;Just generate key code
81 MOV R2,#0 ;Set the state
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
100 SUB PC,R2,#4 ;Do the instruction
102 driver__table DCD 's'
113 B driver__next;driver__alter
133 B driver__next;driver__options
138 ; --- Single Step ---
140 driver__step MOV R0,#229 ;Set escape action
141 MOV R2,#0 ;Set the state to what it was
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
154 driver__cont MOV R0,#229 ;Set escape action
155 MOV R2,#0 ;Set the state to what it was
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
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
168 ; --- Soft emulation ---
172 MOV R0,#229 ;Set escape action
173 MOV R2,#0 ;Set the state to what it was
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
190 ; --- Help display ---
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
197 DCB "Commands available:",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
215 ; --- Set a breakpoint ---
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
223 ; --- Remove a breakpoint ---
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
231 ; --- Remove all breakpoints ---
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
238 driver__kaMsg DCB "Remove all breakpoints?",0
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
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
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
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
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
273 20driver__oscli LDMFD R13!,{R0-R5} ;Unstack registers
274 B driver__next ;And rejoin the main loop
276 ; --- Toggle flags ---
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
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
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
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
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
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
308 driver__flagOff DCB "off.",0
309 driver__flagOn DCB "on.",0
311 ; --- Disassemble context ---
315 LDR R4,[R3,#15*4] ;Load current program count
316 BIC R4,R4,#&FC000003 ;Clear PSR flags
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
322 SUB R5,R0,#40 ;Do 10 instrs each side
323 MOV R6,#21 ;That's 21 instructions total
325 MOV R0,R5 ;Get the disassembly base
326 BL diss_address ;Set disassembly up nicely
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
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
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
347 B driver__next ;Rejoin the main loop
351 ; --- Register dump ---
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
360 ; --- Start the main display loop ---
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
366 ; --- Display a register ---
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
382 ; --- Now display R14 and R15 with PSR bits testually ---
384 SWI OS_NewLine ;Another newline
385 SWI OS_WriteS ;Display immediate stuff
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
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
419 ; --- driver__psr ---
421 ; On entry: R9 == value to display
423 ; On exit: R0-R12 corrupted, maybe
425 ; Use: Displays R9 with PSR bits stripped away, and then with
426 ; all the PSR bits described too.
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
434 SWI OS_WriteS ;Some more spaces
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
453 SWI OS_WriteS ;Yet more stuff
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
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
470 driver__modes DCB "USR",0
475 driver__irqOn DCB ", IRQ",0
476 driver__fiqOn DCB ", FIQ",0
478 driver__writeHex ROUT
480 STMFD R13!,{R0-R2,R14}
487 LDMFD R13!,{R0-R2,PC}^
491 ; --- driver__readAddr ---
495 ; On exit: Error, or CC for no entry, or R0 == address
497 ; Use: Interprets an address as typed by the user.
499 driver__readAddr ROUT
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
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
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
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
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
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
548 05 TST R4,#2 ;Was there a register?
549 BNE %10driver__readAddr ;Yes -- almost done then
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
558 10 TST R4,#1 ;Was there anything at all?
559 BEQ %80driver__readAddr ;No -- return C clear then
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
566 ; --- Lazy user typed nothing ---
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
572 ; --- Stupid user caused an error ---
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
580 ;----- That's all, folks ----------------------------------------------------