don't click here

Generic error debugger + disassembler

Discussion in 'Engineering & Reverse Engineering' started by flamewing, Jan 30, 2014.

  1. flamewing

    flamewing

    Emerald Hunter Tech Member
    1,161
    65
    28
    France
    Sonic Classic Heroes; Sonic 2 Special Stage Editor; Sonic 3&K Heroes (on hold)
    Edit: I made a new version fixing a bug and adding a binary-blob version. See this post for more information. The original post now follows:

    [hr]

    I was going to make this an update to the old topic... but decided it would be best suited to a new topic entirely.

    So, you remember that aging debugger I made for address/bus errors? I updated. A few things that changed:
    • The disassembler is now logically separate from the drawing code and from the debugger (the debugger depends on both of them, the disassembler depends on the drawing code);
    • I made sure that the code almost fully position-independent, meaning a binary blob can possibly be made (but see below);
    • loads of bug fixes;
    • recovers more information from branches and jumps, and does so correctly now for dbCC opcodes;
    • brand new font;
    • handles far more errors than just the address and bus errors (the latter of which I have since learned never happens on a real Genesis...);
    • has code that will make macro haters want to stay away.
    Note: If you use asm68k, you will not be able to build this. I use macros and functions to make the code more maintainable and readable, and asm68k sucks. Badly. And I am not saying this only in regards to macros -- I used to think it was only slightly worse than AS, but now I stand corrected: while I was working on a binary blob to support asm68k, I ran into a serious bug in it that caused it to misassemble the code generating wrong output. It suffices to say that instead of helping, I will mercilessly mock anyone that insists on using asm68k because of their bad decision-making skills.

    There is another warning I must give: I won't give support for anything but the Community disassemblies, so if you insist on using outdated disassemblies, you are on your own.

    With those out of the way: first, let me explain how you will go about generating a listing file. In the previous version, I talked about map files; listing files are much better because they are generated much faster; the S2 and S&K disassemblies disable it by default, though. In S2, you have to edit 3 places: one in s2.macrosetup.asm and the rest in s2.asm; so:
    in s2.macrosetup.asm: find this:
    [68k] listing off[/68k]
    and change it to this:
    [68k] listing purecode[/68k]
    You can also use "on" or "noskipped" instead of "purecode", but I recommend using the latter. So now over to s2.asm, do the same twice. Now whenever you build your hack, a s2.lst file will also be generated.

    For S&K, you have to do the same once in sonic3k.macrosetup.asm, then in sonic3k.asm find this:
    [68k]Z80_Snd_Driver: include "Sound/Z80 Sound Driver.asm"[/68k]
    and change it to this:
    [68k]Z80_Snd_Driver: include "Sound/Z80 Sound Driver.asm"
    listing purecode[/68k]

    Now that you are armed with listing files, time to hook up the new debugger! So go on ahead and grab it here. There are seven files in this archive; only 6 are needed for S2, the seventh is for compatibility with the S&K disassembly. Extract these to your hack's main folder. You can move these around, as long as you edit the includes in the relevant files. You want to add these includes:
    For S2:
    [68k] include "_inc/Debugger.asm"[/68k]

    For S&K:

    [68k] include "skcompat.asm"
    include "Debugger.asm"[/68k]

    These are enough to get everything working; he other files are pulled in automatically. Now the debugger is being assembled inside your hack; you want to setup the interrupt vector table to make use of it:

    In S2: find ";Vectors:" and replace the whole table with this:
    [68k];Vectors:
    dc.l System_Stack , EntryPoint , BusError , AddressError ; 4
    dc.l IllegalInstrError , ZeroDivideError, CHKExceptionError, TRAPVError ; 8
    dc.l PrivilegeViolation, TraceError , LineAEmulation , LineFEmulation ; 12
    dc.l ErrorTrap , ErrorTrap , ErrorTrap , ErrorTrap ; 16
    dc.l ErrorTrap , ErrorTrap , ErrorTrap , ErrorTrap ; 20
    dc.l ErrorTrap , ErrorTrap , ErrorTrap , ErrorTrap ; 24
    dc.l SpuriousException , ErrorTrap , ErrorTrap , ErrorTrap ; 28
    dc.l H_Int , ErrorTrap , V_Int , ErrorTrap ; 32
    dc.l TrapVector , TrapVector , TrapVector , TrapVector ; 36
    dc.l TrapVector , TrapVector , TrapVector , TrapVector ; 40
    dc.l TrapVector , TrapVector , TrapVector , TrapVector ; 44
    dc.l TrapVector , TrapVector , TrapVector , TrapVector ; 48
    dc.l ErrorTrap , ErrorTrap , ErrorTrap , ErrorTrap ; 52
    dc.l ErrorTrap , ErrorTrap , ErrorTrap , ErrorTrap ; 56
    dc.l ErrorTrap , ErrorTrap , ErrorTrap , ErrorTrap ; 60
    dc.l ErrorTrap , ErrorTrap , ErrorTrap , ErrorTrap ; 64[/68k]

    In S&K: find "Vectors:" and replace the whole table with this:
    [68k]Vectors:
    dc.l Vectors , EntryPoint , BusError , AddressError ; 4
    dc.l IllegalInstrError , ZeroDivideError, CHKExceptionError, TRAPVError ; 8
    dc.l PrivilegeViolation, TraceError , LineAEmulation , LineFEmulation ; 12
    dc.l ErrorTrap , ErrorTrap , ErrorTrap , ErrorTrap ; 16
    dc.l ErrorTrap , ErrorTrap , ErrorTrap , ErrorTrap ; 20
    dc.l ErrorTrap , ErrorTrap , ErrorTrap , ErrorTrap ; 24
    dc.l SpuriousException , ErrorTrap , ErrorTrap , ErrorTrap ; 28
    dc.l H_int_jump , ErrorTrap , V_int_jump , ErrorTrap ; 32
    dc.l TrapVector , TrapVector , TrapVector , TrapVector ; 36
    dc.l TrapVector , TrapVector , TrapVector , TrapVector ; 40
    dc.l TrapVector , TrapVector , TrapVector , TrapVector ; 44
    dc.l TrapVector , TrapVector , TrapVector , TrapVector ; 48
    dc.l ErrorTrap , ErrorTrap , ErrorTrap , ErrorTrap ; 52
    dc.l ErrorTrap , ErrorTrap , ErrorTrap , ErrorTrap ; 56
    dc.l ErrorTrap , ErrorTrap , ErrorTrap , ErrorTrap ; 60
    dc.l ErrorTrap , ErrorTrap , ErrorTrap , ErrorTrap ; 64[/68k]

    If you try to assemble and you get errors, it is because you are using an older version of AS; get the new version and replace the ones you have. The Git repositories for the Community disassemblies already have this version, by the way.

    Now you just need to trigger an error to see it in action; but if you do that, you will notice that your name and e-mail are wrong; so open "Debugger.asm" and find the following lines:
    [68k]HackerName: vtstring WHITE,"Your name"
    EMailmsg: vtstring BLUE ,"[email protected]"[/68k]
    Except that the e-mail will not be in yellow and underlined, that is just the forum software being an ass. Anyway, supported colors are WHITE, RED, GREEN and BLUE; you can edit the text at will, but your name should not exceed 11 characters -- this is all the space available in the current setup. As the comment near this says, you can use any of the characters int he ASCII set.

    Another thing to do is edit the value of the "Revision" constant in the same file -- this number can be used to uniquely identify the version in which the error happened, so you will know if you already fixed the error or not.

    When all is said and done, this is what you will see (using two manufactured examples):
    [​IMG] [​IMG]

    As a bonus: since the code is logically separate, the disassembler can be used on its own; here is an example of a minimal disassembler that can be build using it:
    [​IMG]

    This was done with this code:
    [68k]DisassemblyTest:
    bsr.w InitTerminal
    lea DrawTerminal(pc),a3
    tellp.l -(sp) ; Save end of buffer
    setcursor DisassemblyAlign,0

    .instr_loop: shared .instr_loop
    move.l (sp),d0 ; Get end of screen buffer
    vtchkp.l d0 ; Is this after current position?
    blo.w .draw_terminal ; Branch if not
    tellp.l -(sp) ; Save start of line
    move.w (a3)+,d5 ; Read instruction
    lea RewindStub(pc),a4 ; Pointer to rts
    bsr.w Disassemble_Opcode
    movea.l a2,a3 ; PC for next instruction
    tellp.l d0 ; Save current position on buffer
    seekset (sp)+ ; Seek back to old position

    .next_line:
    seekp.l nCols ; Advance it by one line
    vtchkp.l d0 ; Is this after current position on buffer?
    bhs.s .next_line ; Branch if not
    bra.s .instr_loop
    ;---------------------------------------------------------------------------------------
    .draw_terminal:
    addq.w #4,sp ; Pop end of screen buffer from stack
    bsr.w DrawTerminal

    .error_trap:
    nop
    nop
    bra.s .error_trap
    ; ===========================================================================[/68k]
     
  2. flamewing

    flamewing

    Emerald Hunter Tech Member
    1,161
    65
    28
    France
    Sonic Classic Heroes; Sonic 2 Special Stage Editor; Sonic 3&K Heroes (on hold)
    It has been pointed out that the version of AS in the Community disassemblies is a bit outdated, and does not have a function I used in the macros; I compiled a new version that handles it just fine, and I will be uploading it to the repositories soon.

    Edit: The community repositories are now up to date.
     
  3. Tiddles

    Tiddles

    Diamond Dust Tech Member
    471
    0
    0
    Leicester, England
    Get in an accident and wake up in 1973
    I made an alternative font for this, because I am endlessly nostalgic for the early days of teletext and the BBC Micro. This is based on the characters you would have got out of an SAA5050. The descenders are squashed because it's a bit too tall for 8x8, but it's otherwise very faithful.

    [​IMG]

    [​IMG]

    Download (Kosinski-compressed tiles)
     
  4. FireRat

    FireRat

    Nah. Fuck it. Banned
    48
    10
    8
    Chile
    Mobius Evolution 2
    Excuse me for bumping this up, but I have just noticed a little issue trying to build it for my SegaCD hack:

    Code (ASM):
    1.  
    2.     subi.w  #System_Stack,d3            ; d3 = -1 * number of bytes to print
    3.  
    This line gave me a little error, which I fixed this way...

    Code (ASM):
    1.  
    2.     subi.w  #(System_Stack)&$FFFF,d3        ; d3 = -1 * number of bytes to print
    3.  
    I know this may look insignificant, but you know, perhaps not everybody knows about it or whatever :v

    * NOTE: I'm using the 1.42 (beta, build 92) version (Win32).
     
  5. flamewing

    flamewing

    Emerald Hunter Tech Member
    1,161
    65
    28
    France
    Sonic Classic Heroes; Sonic 2 Special Stage Editor; Sonic 3&K Heroes (on hold)
    The error is because the System_Stack constant was not defined as a negative value, preventing AS from recognizing it can be sign-extended. This most likely happened because you defined it as a 32-bit (or less) hex value, whereas AS uses 64-bit arithmetic internally (because of other processors, most likely). Look at how the S2 and S&K disassemblies handle that for another way of making it work.
     
  6. flamewing

    flamewing

    Emerald Hunter Tech Member
    1,161
    65
    28
    France
    Sonic Classic Heroes; Sonic 2 Special Stage Editor; Sonic 3&K Heroes (on hold)
    So, a double-post with an update: I found and fixed a nasty bug in the disassembler in one case of an illegal instruction which could cause the disassembler to overwrite a good chunk of RAM.

    I also went back at ASM68K, and managed to beat it into submission, so folks who can't (or won't, for some reason) switch to a less sucky assembler can now use a binary blob with a smidge of customizability.

    So, the links:

    For the full source: click here.
    For the binary blob: click here.

    Instructions for the source version are unchanged. For the binary blob, here is what you should do:

    First, configure ASM68K to output a listing. This is done by editing the build script; it should have a line that looks like this:
    Code (Text):
    1. asm68k /k /p /o ae- sonic.asm, s1built.bin >errors.txt
    Change it to this:
    Code (Text):
    1. asm68k /k /p /o ae- sonic.asm, s1built.bin >errors.txt, , sonic.lst
    If it already has the added bits, it was generating a listing file already, so you don't need to do this.

    Next, download the binary blob and extract it to a folder called "_debugger" in your disassembly; it will not be there by default, so you will have to create it (doh).

    Now include the blob includer:
    [68k] include "_debugger\DebuggerBlob.asm"[/68k]

    somewhere in your disassembly. Parts of this file can be edited: you can edit these lines:
    [68k] jmp (KosDec).l
    jmp (EniDec).l[/68k]
    to point to the correct targets, you can edit the variables HackerName, EMailmsg and Revision; read the comments before you edit them. Make sure to not change the spacing before stuff, of the blob will fail.

    Next step is to remove the old debugger (S1 only) or it will conflict with some names used in the blob. To do this, find the line
    [68k]BusError:[/68k]
    Then find this line:
    [68k]; End of function sub_5CA[/68k]
    and delete everything from the first line up until this line. It is now time to hook up the debugger. Find this:
    [68k]Vectors: dc.l $FFFE00, EntryPoint, BusError, AddressError
    dc.l IllegalInstr, ZeroDivide, ChkInstr, TrapvInstr
    dc.l PrivilegeViol, Trace, Line1010Emu, Line1111Emu
    dc.l ErrorExcept, ErrorExcept, ErrorExcept, ErrorExcept
    dc.l ErrorExcept, ErrorExcept, ErrorExcept, ErrorExcept
    dc.l ErrorExcept, ErrorExcept, ErrorExcept, ErrorExcept
    dc.l ErrorExcept, ErrorTrap, ErrorTrap, ErrorTrap
    dc.l HBlank, ErrorTrap, VBlank, ErrorTrap
    dc.l ErrorTrap, ErrorTrap, ErrorTrap, ErrorTrap
    dc.l ErrorTrap, ErrorTrap, ErrorTrap, ErrorTrap
    dc.l ErrorTrap, ErrorTrap, ErrorTrap, ErrorTrap
    dc.l ErrorTrap, ErrorTrap, ErrorTrap, ErrorTrap
    dc.l ErrorTrap, ErrorTrap, ErrorTrap, ErrorTrap
    dc.l ErrorTrap, ErrorTrap, ErrorTrap, ErrorTrap
    dc.l ErrorTrap, ErrorTrap, ErrorTrap, ErrorTrap
    dc.l ErrorTrap, ErrorTrap, ErrorTrap, ErrorTrap[/68k]
    (HBlank may be with different name depending on how outdated a disassembly you are basing your work on) and edit it to match this:
    [68k]Vectors: dc.l $FFFE00, EntryPoint, BusError, AddressError
    dc.l IllegalInstrError, ZeroDivideError, CHKExceptionError, TRAPVError
    dc.l PrivilegeViolation, TraceError, LineAEmulation, LineFEmulation
    dc.l ErrorTrap, ErrorTrap, ErrorTrap, ErrorTrap
    dc.l ErrorTrap, ErrorTrap, ErrorTrap, ErrorTrap
    dc.l ErrorTrap, ErrorTrap, ErrorTrap, ErrorTrap
    dc.l SpuriousException, ErrorTrap, ErrorTrap, ErrorTrap
    dc.l HBlank, ErrorTrap, VBlank, ErrorTrap
    dc.l TrapVector, TrapVector, TrapVector, TrapVector
    dc.l TrapVector, TrapVector, TrapVector, TrapVector
    dc.l TrapVector, TrapVector, TrapVector, TrapVector
    dc.l TrapVector, TrapVector, TrapVector, TrapVector
    dc.l ErrorTrap, ErrorTrap, ErrorTrap, ErrorTrap
    dc.l ErrorTrap, ErrorTrap, ErrorTrap, ErrorTrap
    dc.l ErrorTrap, ErrorTrap, ErrorTrap, ErrorTrap
    dc.l ErrorTrap, ErrorTrap, ErrorTrap, ErrorTrap[/68k]
    The debugger should be working now, unless I forgot a step on the guide. Please let me know if I did and I will update it.
     
  7. Hitaxas

    Hitaxas

    Retro 80's themed Twitch streamer ( on hiatus) Member
    Slight bumping to report that when I attempted to use this, and built the game I got a ton of errors thrown in my face. My build.bat (using AS not ASM68K) states pretty much every offset table from NegX_Clr_Neg_Notmsgs and down presents an unknown opcode error. Not sure why, seeing as how the offset tables before that do not have such an error.
     
  8. flamewing

    flamewing

    Emerald Hunter Tech Member
    1,161
    65
    28
    France
    Sonic Classic Heroes; Sonic 2 Special Stage Editor; Sonic 3&K Heroes (on hold)
    Have you tried using the new version of AS from the second post I made? I need to update the posts before to mention it.
     
  9. Hitaxas

    Hitaxas

    Retro 80's themed Twitch streamer ( on hiatus) Member
    Even using the new version of AS I get the same exact errors.

    Edit: Basically getting around 140 errors like this:
    Code (ASM):
    1. > > > OFFSETTABLE
    2. > > > NegX_Clr_Neg_Notmsgs:       offsetTable
    3. > > >_inc/disassembler2.asm(3): error: unknown opcode
    4. > > > OFFSETTABLEENTRY
    5. > > >   offsetTableEntry.w        NegXmsg
    6. > > >_inc/disassembler2.asm(4): error: unknown opcode
    7. > > > OFFSETTABLEENTRY
    8. > > >   offsetTableEntry.w        Clrmsg
    9. > > >_inc/disassembler2.asm(5): error: unknown opcode
    10. > > > OFFSETTABLEENTRY
    11. > > >   offsetTableEntry.w        Negmsg
    12. > > >_inc/disassembler2.asm(6): error: unknown opcode
    13. > > > OFFSETTABLEENTRY
    14. > > >   offsetTableEntry.w        Notmsg
    15. > > >_inc/disassembler2.asm(14): error: unknown opcode
    16. > > > OFFSETTABLE
    17. > > > Reset_Nop_Stop_Rte_Rts_TrapV_Rtrmsgs:     offsetTable
    18. > > >_inc/disassembler2.asm(15): error: unknown opcode
    19. > > > OFFSETTABLEENTRY
    20. > > >           offsetTableEntry.w Resetmsg
    21. > > >_inc/disassembler2.asm(16): error: unknown opcode
     
  10. flamewing

    flamewing

    Emerald Hunter Tech Member
    1,161
    65
    28
    France
    Sonic Classic Heroes; Sonic 2 Special Stage Editor; Sonic 3&K Heroes (on hold)
    Hm. AS generally emits this error only when the macro has not been defined (assemblers in general implement macros as pseudo-instructions).
     
  11. Hitaxas

    Hitaxas

    Retro 80's themed Twitch streamer ( on hiatus) Member
    But I'd assume that the macro is defined due to the rest not throwing errors at me... So what could possibly cause this?
     
  12. flamewing

    flamewing

    Emerald Hunter Tech Member
    1,161
    65
    28
    France
    Sonic Classic Heroes; Sonic 2 Special Stage Editor; Sonic 3&K Heroes (on hold)
    Lets see: including the debugger before the macro definitions would be one, but I doubt this is it; hrm. See PM.
     
  13. TheInvisibleSun

    TheInvisibleSun

    OVER THE TOP TECHNO-BLAST Member
    1,626
    193
    43
    Buffalo, NY, USA
    The Water
    This is pretty awesome! I actually didn't even know about this until a few days ago; thanks for making this flamewing.

    A couple of things in the blob to note though (nothing too serious, but I guess should be mentioned):

    -The include for Part 1 doesn't point to the _debugger folder by default.

    -The 'Revision' label in the debugger is used already in sonic.asm (for Sonic 1, at least), perhaps it can use a different name, like RevisionNumber?

    Again, not serious problems at all (as they are fixable by anyone in a matter of seconds), but I felt they should be mentioned.
     
  14. flamewing

    flamewing

    Emerald Hunter Tech Member
    1,161
    65
    28
    France
    Sonic Classic Heroes; Sonic 2 Special Stage Editor; Sonic 3&K Heroes (on hold)
    I updated the debugger blob version using these suggestions. The links above now download the new version, but you can just click here for convenience.