udis86sx/UDIS86.st
author Jan Vrany <jan.vrany@fit.cvut.cz>
Mon, 11 Jan 2016 21:44:00 +0000
changeset 6 ff36d8318020
parent 1 aa002d0c231b
child 23 d2d9a2d4d6bf
permissions -rw-r--r--
Added utility method UDIS86 class>>disassemble: ...to quickly disassemble a buffer containing machine code.

"{ Package: 'jv:dragonfly/udis86sx' }"

"{ NameSpace: Smalltalk }"

Object subclass:#UDIS86
	instanceVariableNames:'handle buffer'
	classVariableNames:''
	poolDictionaries:''
	category:'UDIS86'
!

!UDIS86 primitiveDefinitions!
%{

/*
 * includes, defines, structure definitions
 * and typedefs come here.
 */

#include <udis86.h>

#define ud ((ud_t*)(&__byteArrayVal( __INST(handle) )))

%}
! !

!UDIS86 class methodsFor:'documentation'!

documentation
"
    Intel X86 disassembler for both i386 and x86_64 code.
    Based on Vivek Thampi's udis86 C library

    [author:]
        Jan Vrany <jan.vrany@fit.cvut.cz>

    [instance variables:]

    [class variables:]

    [see also:]
        udis86 https://github.com/vmt/udis86

"
! !

!UDIS86 class methodsFor:'instance creation'!

new
    "return an initialized instance"

    ^ self basicNew initialize.
! !

!UDIS86 class methodsFor:'examples'!

example1
    | code disas insn |

    code := #[ 16r81 16rc3 16r9d 16r12 16r00 16r00  "/ add    $0x129d,%ebx
               16r68 16r40 16r94 16r04 16r08        "/ push   $0x8049440
               16re8 16r6f 16rfe 16rff 16rff        "/  call   8048310
            ]. 
    disas := UDIS86 new.
    disas buffer: code pc: 16r00FF0000.

    "/ Disassemble the code, print assembly
    "/ on Transcript
    [ (insn := disas disassemble) notNil ] whileTrue:[
        Transcript showCR: insn printString.
    ]

    "
    UDIS86 example1
    "

    "Created: / 10-12-2015 / 16:54:21 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 11-12-2015 / 21:30:33 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!UDIS86 class methodsFor:'utilities'!

disassemble: buffer
    ^ String streamContents:[ :s | self disassemble: buffer on: s ]

    "Created: / 11-01-2016 / 20:58:21 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

disassemble: buffer on: stream
    self disassemble: buffer pc: 0 on: stream

    "Created: / 11-12-2015 / 10:15:49 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 11-12-2015 / 21:32:22 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

disassemble: buffer pc: pc on: stream
    | disasm insn |

    disasm := UDIS86 new.
    disasm buffer: buffer pc: pc.
    [ (insn := disasm disassemble) notNil ] whileTrue:[ 
        stream nextPutLine: insn printString
    ].

    "Created: / 11-12-2015 / 21:32:07 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!UDIS86 methodsFor:'accessing'!

buffer: aByteArrayOrExternalBytes
    "Set the input buffer containing instructions for
     disassembling."

    | buff pc |

    buff := aByteArrayOrExternalBytes asExternalBytes.
    aByteArrayOrExternalBytes isExternalBytes ifTrue:[ 
        pc := aByteArrayOrExternalBytes address.
    ].
    self buffer: buff pc: pc

    "Created: / 09-12-2015 / 22:54:02 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 11-12-2015 / 16:10:57 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

buffer: aByteArray pc: anInteger
    "Set the input buffer containing instructions for
     disassembling."

    | bufferLen pc |

    buffer := aByteArray asExternalBytes.
    bufferLen := buffer size.
    pc := anInteger ? 0.
%{
    if ( __isExternalAddressLike( _INST( buffer ) ) &&
         __isSmallInteger( bufferLen ) &&
         __isSmallInteger( pc ) ) {
        ud_set_input_buffer(ud, __externalAddressVal( __INST( buffer ) ), __intVal( bufferLen ) );
        ud_set_pc(ud, __intVal( pc ) );
        RETURN ( self );
    }
%}.
    self primitiveFailed

    "Created: / 11-12-2015 / 16:07:24 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 11-12-2015 / 21:20:54 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

mode: anInteger
    "Sets the mode of disassembly. Possible values are 16, 32, and 64. 
     By default it uses 32bit mode when running VM is 32bit, 64bit if
     it's 64bit one"

    self assert: (#(16 32 64) includes: anInteger).
%{
    ud_set_mode( ud, __intVal ( anInteger ) );
%}.

    "Created: / 09-12-2015 / 23:01:40 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

useSyntaxATT
    "Sets AT&T syntax for assembly.
     See http://www.imada.sdu.dk/Courses/DM18/Litteratur/IntelnATT.htm"
%{
    ud_set_syntax ( ud, UD_SYN_ATT );
%}

    "Created: / 10-12-2015 / 21:34:00 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

useSyntaxIntel
    "Sets Intel syntax for assembly.
     See http://www.imada.sdu.dk/Courses/DM18/Litteratur/IntelnATT.htm"
%{
    ud_set_syntax ( ud, UD_SYN_INTEL );
%}

    "Created: / 10-12-2015 / 21:33:40 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!UDIS86 methodsFor:'disassembling'!

disassemble
    "Disassembles the next instruction in the input buffer/stream.
     Returns the number of bytes disassembled. A 0 indicates end of input."

    | pc opcodeCode assembly |
%{
    if (! ud_disassemble ( ud ) ) { 
        RETURN (nil);
    }
    opcodeCode = __MKSMALLINT( ud_insn_mnemonic ( ud ) );
    assembly = __MKSTRING( ud_insn_asm ( ud ) );
    pc = __MKSMALLINT( ud_insn_off ( ud ) );
%}.
    ^ UDIS86Instruction new
        setAssembly: assembly;
        setPC: pc;
        setOpcodeCode: opcodeCode;    

        yourself.

    "Created: / 09-12-2015 / 22:57:05 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 11-12-2015 / 21:23:00 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!UDIS86 methodsFor:'initialization'!

initialize
    | handleSize |

%{
    handleSize = __MKSMALLINT( sizeof( ud_t ) );
%}.
    handle := ByteArray new: handleSize.
%{
    ud_init( ud );
    ud_set_syntax ( ud, UD_SYN_INTEL );
%}.
    ExternalAddress pointerSize == 8 ifTrue:[ 
        self mode: 64.
    ] ifFalse:[ 
        self mode: 32.
    ].

    "
    UDIS86 new
    "

    "Modified: / 10-12-2015 / 21:26:59 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!UDIS86 class methodsFor:'documentation'!

version_HG

    ^ '$Changeset: <not expanded> $'
! !