aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDrahflow <drahflow@gmx.de>2014-05-28 00:21:19 +0200
committerDrahflow <drahflow@gmx.de>2014-05-28 00:21:19 +0200
commit8df51c3d165c9c225e51d502b8816998f25ea2a2 (patch)
tree932d37ece575157b33bc33273d6c2218778a447d
parent67450c10e3cce51ea1204cee511902c25b725fad (diff)
Initial commit.
-rw-r--r--samyle/cmdline.ey56
-rw-r--r--samyle/decoder-tests.ey18
-rw-r--r--samyle/decoder.ey423
-rw-r--r--samyle/disasm.ey115
-rw-r--r--samyle/elf.ey117
-rw-r--r--samyle/hexedit.ey34
-rw-r--r--samyle/locations-test.ey6
-rw-r--r--samyle/locations.ey24
-rw-r--r--samyle/main.ey33
-rw-r--r--samyle/screens.ey15
-rw-r--r--samyle/terminal.ey34
-rw-r--r--samyle/utils.ey39
-rw-r--r--samyle/welcome.ey16
13 files changed, 930 insertions, 0 deletions
diff --git a/samyle/cmdline.ey b/samyle/cmdline.ey
new file mode 100644
index 0000000..c2282a2
--- /dev/null
+++ b/samyle/cmdline.ey
@@ -0,0 +1,56 @@
+<
+ terminal "$" via
+ sys .linux "+" via
+
+ "" ==input
+
+ {
+ "" =input
+ display
+ } /init deffd
+
+ { ==k
+ 0 10 $goto 0 k * txt .produce .u $out
+ [
+ { 0 k * 10 eq } { input execute init }
+ { 0 k * 127 eq } { 1 neg input str .prefix =input }
+ { 1 } { input k cat =input }
+ ] conds
+ display
+ } /handle deffd
+
+ { _ ==cmd " " str .split =*args
+ [
+ { cmd len 0 eq } { "No command specified." $err }
+ { 0 args "q" eq } { 0 =running }
+ { 0 args "r" eq } {
+ |args len 2 neq { "Use :r <filename>" $err } {
+ 1 args "\0" cat +ORDONLY 0 +open ==fd
+ fd 0 le { "Could not open file" $err } {
+ fd +fstat -- .size ==size
+ 0 size +PROTREAD +MAPPRIVATE fd 0 +mmap ==addr
+ "Loaded at address " addr txt .produce .hu cat $info
+
+ addr locations .cursor .gotoByte
+ screens .|hexedit screens .enter
+ } ? *
+ } ? *
+ }
+ { 0 args "e" eq } {
+ |args len 2 neq { "Use :e <filename.elf>" $err } {
+ 1 args elf .load
+ screens .|disasm screens .enter
+ } ? *
+ }
+ { 0 args "d" eq } { screens .|disasm screens .enter }
+ ] conds
+ } /execute deffd
+
+ {
+ 0 25 $goto $clearLine ":" $out input $out
+ } /display deffd
+
+ { _ "" eq |init |handle ? * }
+> -- /cmdline deffd
+
+# vim: syn=elymas
diff --git a/samyle/decoder-tests.ey b/samyle/decoder-tests.ey
new file mode 100644
index 0000000..06a2056
--- /dev/null
+++ b/samyle/decoder-tests.ey
@@ -0,0 +1,18 @@
+txt .consume .|hu "%" defq
+
+[ ] =*memory
+
+< > /utils defvd
+
+"decoder.ey" include
+
+[ %31 %ED ] =memory # xor %ebp, %ebp
+
+0 decoder .fromAddress ==instr
+instr .txt _ dump "xor %ebp, %ebp" eq assert
+instr .partCount _ dump 4 eq assert
+0 instr .txtPartSelect -12 -- _ dump "xor %ebp, %ebp" eq assert
+1 instr .txtPartSelect -12 -- _ dump "xor" eq assert
+2 instr .txtPartSelect -12 -- _ dump "%ebp" eq assert
+3 instr .txtPartSelect -12 -- _ dump "%ebp" eq assert
+4 instr .txtPartSelect -12 -- _ dump "" eq assert
diff --git a/samyle/decoder.ey b/samyle/decoder.ey
new file mode 100644
index 0000000..2a160d5
--- /dev/null
+++ b/samyle/decoder.ey
@@ -0,0 +1,423 @@
+<
+ utils "$$" via
+ txt .consume .|hu "%" defq
+ txt .produce "$>" via
+ sys .linux "+" via
+
+ 0 ==:GPR
+
+ { <
+ _ ==startA ==a
+ 0 ==prefix66
+ 0 ==prefix67
+ 0 ==operandWidth
+ 64 ==addressWidth
+ 0 ==rex
+ 0 ==rexW
+ 0 ==rexB
+ 0 ==rexR
+ 0 ==rexX
+ 1 neg ==rm
+ 1 neg ==reg
+ 1 neg ==mode
+ 1 neg ==dir
+ 1 neg ==imm
+ 1 neg ==target
+ 1 neg ==scale
+ 1 neg ==base
+ 1 neg ==idx
+ 0 ==hasDisp
+ 1 neg ==disp
+ 1 neg ==immWidth
+ 0 ==hasImmediate
+ "???" ==instruction
+ { [ instruction ] } /parts deffst
+
+ { _ sys .typed .type 7 eq { |partsToTxt each } |cat ? * } /partsToTxt deffst
+ { "" parts partsToTxt } /txt deffst
+
+ { _ sys .typed .type 7 eq { |partsToCount each 1 add } { -- } ? * } /partsToCount deffst
+ { 0 parts partsToCount } /partCount deffst
+
+ { ==selected 0 ==any 0 ==p
+ { 0 ==sel _ sys .typed .type 7 eq {
+ selected p eq _ =sel { "" -01 1 =any } rep p 1 add =p |partsToTxtSelect each sel { "" } rep } |cat ? *
+ } /partsToTxtSelect deffst
+ "" parts partsToTxtSelect
+ any not { "" "" } rep
+ } /txtPartSelect deffst
+
+ 1 ==prefixDecoding
+ { prefixDecoding 0 =prefixDecoding } {
+ a $$memory %66 eq { 1 =prefix66 a 1 add =a 1 =prefixDecoding } rep
+ a $$memory %67 eq { 1 =prefix67 a 1 add =a 1 =prefixDecoding } rep
+ } loop
+
+ prefix67 { 32 =addressWidth } rep
+
+ a $$memory %F0 band %40 eq {
+ a $$memory =rex
+ rex 1 band 1 0 ? =rexB
+ rex 2 band 1 0 ? =rexX
+ rex 4 band 1 0 ? =rexR
+ rex 8 band 1 0 ? =rexW
+ a 1 add =a
+ } rep
+
+ { ==a
+ a $$memory ==sib
+ sib %07 band rexB 8 mul add =base
+ sib %38 band 8 div rexX 8 mul add =idx
+ sib %C0 band 64 div [ 1 2 4 8 ] * =scale
+
+ idx 4 eq { 1 neg =idx } rep
+ idx 5 eq { 1 neg =base } rep
+
+ a 1 add =a
+ a
+ } /decodeSib deffst
+
+ { ==a
+ a $$memory ==modrm
+ modrm %07 band rexB 8 mul add _ =rm =base
+ modrm %38 band 8 div rexR 8 mul add =reg
+ modrm %C0 band 64 div =mode
+ a 1 add =a
+
+ mode 3 eq { 1 neg =base } rep
+
+ mode 3 neq rm 7 band 4 eq and {
+ a decodeSib =a
+ } rep
+ mode 2 eq {
+ a a 4 add range $$memory 256 math .unbase =disp 1 =hasDisp a 4 add =a
+ disp 2147483648 ge { disp 4294967296 neg bor =disp } rep
+ } rep
+ mode 1 eq {
+ a $$memory =disp 1 =hasDisp a 1 add =a
+ disp 128 ge { disp 256 neg bor =disp } rep
+ } rep
+ mode 0 eq rm 5 eq and {
+ a a 4 add range $$memory 256 math .unbase =disp 1 =hasDisp a 4 add =a
+ disp 2147483648 ge { disp 4294967296 neg bor =disp } rep
+ 16 =base
+ } rep
+
+ a
+ } /decodeRegisterModrm deffst
+
+ { ==width ==reg
+ [
+ { 8 width eq } { reg [ /al /cl /dl /bl ] rex [ /spl /bpl /sil /dil ] [ /ah /ch /dh /bh ] ? cat
+ [ /r8l /r9l /r10l /r11l /r12l /r13l /r14l /r15l "??? [rip 8 bit]" ] cat * }
+ { 16 width eq } { reg [ /ax /cx /dx /bx /sp /bp /si /di /r8w /r9w /r10w /r11w /r12w /r13w /r14w /r15w "??? [rip 16 bit]" ] * }
+ { 32 width eq } { reg [ /eax /ecx /edx /ebx /esp /ebp /esi /edi /r8d /r9d /r10d /r11d /r12d /r13d /r14d /r15d "??? [rip 32 bit]" ] * }
+ { 64 width eq } { reg [ /rax /rcx /rdx /rbx /rsp /rbp /rsi /rdi /r8 /r9 /r10 /r11 /r12 /r13 /r14 /r15 /rip ] * }
+ { 1 } { "??? [gprName]" }
+ ] conds
+ } /gprName deffd
+
+ { a startA sub } /length deffst
+ { [ [ instruction ] " " dir { gprRmParts ", " gprRegParts } { gprRegParts ", " gprRmParts } ? * ] } /gpi2opParts deffst
+ { [ "%" reg operandWidth gprName cat ] } /gprRegParts deffst
+ { [
+ { mode 3 eq } { [ "%" rm operandWidth gprName cat ] }
+ { mode 3 lt } { [
+ hasDisp { disp dispParts } rep
+ base 0 ge idx 0 ge or { "("
+ base 0 ge { [ "%" base addressWidth gprName ] } rep
+ idx 0 ge {
+ ", " [ "%" idx addressWidth gprName ]
+ scale 1 neq { ", " [ scale $>u ] } rep
+ } rep
+ ")" } rep
+ ] }
+ { 1 } { "??? [rm]" }
+ ] conds } /gprRmParts deffst
+ { # ==n
+ _ [ -01 16 mod "0123456789abcdef" * ] str .fromArray
+ -01 16 div
+ } /extractHexDigit deffd
+ { ==n [ [
+ { operandWidth 8 eq } { [ n 2 |extractHexDigit rep -- "$0x" ] reverse |cat fold }
+ { operandWidth 16 eq } { [ n 4 |extractHexDigit rep -- "$0x" ] reverse |cat fold }
+ { operandWidth 32 eq } { [ n 8 |extractHexDigit rep -- "$0x" ] reverse |cat fold }
+ { operandWidth 64 eq } { [ n 16 |extractHexDigit rep -- "$0x" ] reverse |cat fold }
+ { 1 } { "??? [immParts]" }
+ ] conds ] } /immParts deffst
+ { ==n [ [
+ { addressWidth 8 eq } { [ n 2 |extractHexDigit rep -- "$0x" ] reverse |cat fold }
+ { addressWidth 16 eq } { [ n 4 |extractHexDigit rep -- "$0x" ] reverse |cat fold }
+ { addressWidth 32 eq } { [ n 8 |extractHexDigit rep -- "$0x" ] reverse |cat fold }
+ { addressWidth 64 eq } { [ n 16 |extractHexDigit rep -- "$0x" ] reverse |cat fold }
+ { 1 } { "??? [dispParts]" }
+ ] conds ] } /dispParts deffst
+ { [
+ target $>hu _ locations .names .has {
+ _ " = " cat -01 locations .names * cat
+ } rep
+ ] } /targetParts deffst
+
+ {
+ 32 =operandWidth
+ prefix66 { 16 =operandWidth } { } ? *
+ rex { 64 =operandWidth } { } ? *
+
+ |gpi2opParts =parts
+ a decodeRegisterModrm =a
+ } /gpi2Op deffst
+ {
+ 8 =operandWidth
+
+ |gpi2opParts =parts
+ a decodeRegisterModrm =a
+ } /gpi82Op deffst
+ {
+ 32 =operandWidth
+ prefix66 { 16 =operandWidth } { } ? *
+ rex { 64 =operandWidth } { } ? *
+
+ { [ [ instruction ] " " gprRmParts ] } =parts
+ a decodeRegisterModrm =a
+ } /gpi1Op deffst
+ {
+ 32 =operandWidth
+ prefix66 { 16 =operandWidth } { } ? *
+ rex { 64 =operandWidth } { } ? *
+
+ a decodeRegisterModrm =a 1 neg =reg # register field used to select opcodes
+ 1 =hasImmediate
+ a $$memory =imm a 1 add =a
+ { [ [ instruction ] " " imm immParts ", " gprRmParts ] } =parts
+ imm 128 ge { imm 256 neg bor =imm } rep
+ } /gpiImm8Op deffst
+ {
+ 8 =operandWidth
+
+ a decodeRegisterModrm =a 1 neg =reg # register field used to select opcodes
+ 1 =hasImmediate
+ a $$memory =imm a 1 add =a
+ { [ [ instruction ] " " imm immParts ", " gprRmParts ] } =parts
+ imm 128 ge { imm 256 neg bor =imm } rep
+ } /gpi8ImmOp deffst
+ {
+ 32 =operandWidth
+ prefix66 { 16 =operandWidth } { } ? *
+ rex { 64 =operandWidth } { } ? *
+
+ a decodeRegisterModrm =a 1 neg =reg # register field used to select opcodes
+ 1 =hasImmediate
+ operandWidth 64 eq 32 operandWidth ? =immWidth
+ a a immWidth 8 div add range $$memory 256 math .unbase =imm a immWidth 8 div add =a
+ { [ [ instruction ] " " imm immParts ", " gprRmParts ] } =parts
+ operandWidth 64 eq imm 2147483648 ge and { imm 4294967296 neg bor =imm } rep
+ } /gpiImmOp deffst
+ {
+ { [ [ instruction ] " " gprRegParts ] } =parts
+ 64 =operandWidth
+ } /popOp deffst
+ {
+ 32 =operandWidth
+ prefix66 { 16 =operandWidth } { } ? *
+ rex { 64 =operandWidth } { } ? *
+
+ 1 =hasImmediate
+ operandWidth =immWidth
+ a a immWidth 8 div add range $$memory 256 math .unbase =imm a immWidth 8 div add =a
+ { [ [ instruction ] " " imm immParts ", " gprRegParts ] } =parts
+ } /movIOp deffst
+ {
+ 32 _ =operandWidth =immWidth
+ prefix66 { 16 _ =operandWidth =immWidth } { } ? *
+ rex { 64 =operandWidth } { } ? *
+ 0 =reg
+
+ 1 =hasImmediate
+ a a immWidth 8 div add range $$memory 256 math .unbase =imm a immWidth 8 div add =a
+ immWidth 32 eq imm 2147483648 ge and { imm 4294967296 neg bor =imm } rep
+ immWidth 16 eq imm 32768 ge and { imm 65536 neg bor =imm } rep
+ { [ [ instruction ] " " imm immParts ", " gprRegParts ] } =parts
+ } /axImmOp deffst
+ {
+ 8 _ =operandWidth =immWidth
+ 0 =reg
+
+ 1 =hasImmediate
+ a a immWidth 8 div add range $$memory 256 math .unbase =imm a immWidth 8 div add =a
+ imm 128 ge { imm 256 neg bor =imm } rep
+ { [ [ instruction ] " " imm immParts ", " gprRegParts ] } =parts
+ } /ax8ImmOp deffst
+ {
+ 64 =operandWidth
+ 32 =immWidth
+ prefix66 { 16 =immWidth } { } ? *
+
+ a a immWidth 8 div add range $$memory 256 math .unbase =imm a immWidth 8 div add =a
+ immWidth 32 eq imm 2147483648 ge and { imm 4294967296 neg bor =imm } rep
+ immWidth 16 eq imm 32768 ge and { imm 65536 neg bor =imm } rep
+ { [ [ instruction ] " " targetParts ] } =parts
+ a imm add =target
+ } /callOp deffst
+ {
+ { [ instruction ] } =parts
+ } /trivialOp deffst
+ {
+ 64 =operandWidth
+ 8 =immWidth
+ a $$memory =imm a 1 add =a
+ imm 128 ge { imm 256 neg bor =imm } rep
+ { [ [ instruction ] " " targetParts ] } =parts
+ a imm add =target
+ } /jcc8Op deffst
+
+ a $$memory ==opcode
+ a 1 add =a
+ a $$memory _ ==secondaryOpcode
+ %38 band 8 div ==modrmOpcode
+ a 1 add $$memory %38 band 8 div ==modrmOpcode2
+
+ [
+ { opcode %00 eq } { "add" =instruction 0 =dir gpi82Op }
+ { opcode %01 eq } { "add" =instruction 0 =dir gpi2Op }
+ { opcode %02 eq } { "add" =instruction 1 =dir gpi82Op }
+ { opcode %03 eq } { "add" =instruction 1 =dir gpi2Op }
+ { opcode %04 eq } { "add" =instruction ax8ImmOp }
+ { opcode %05 eq } { "add" =instruction axImmOp }
+ { opcode %06 eq } { "push %es (invalid in 64bit)" trivialOp }
+ { opcode %07 eq } { "pop %es (invalid in 64bit)" trivialOp }
+ { opcode %08 eq } { "or" =instruction 0 =dir gpi82Op }
+ { opcode %09 eq } { "or" =instruction 0 =dir gpi2Op }
+ { opcode %0A eq } { "or" =instruction 1 =dir gpi82Op }
+ { opcode %0B eq } { "or" =instruction 1 =dir gpi2Op }
+ { opcode %0C eq } { "or" =instruction ax8ImmOp }
+ { opcode %0D eq } { "or" =instruction axImmOp }
+ { opcode %0E eq } { "push %cs (invalid in 64bit)" trivialOp }
+ { opcode %0F eq secondaryOpcode %1F eq and modrmOpcode2 0 eq and } { a 1 add =a "nop" =instruction gpi1Op }
+ # TODO insert secondary opcode map
+
+ { opcode %10 eq } { "adc" =instruction 0 =dir gpi82Op }
+ { opcode %11 eq } { "adc" =instruction 0 =dir gpi2Op }
+ { opcode %12 eq } { "adc" =instruction 1 =dir gpi82Op }
+ { opcode %13 eq } { "adc" =instruction 1 =dir gpi2Op }
+ { opcode %14 eq } { "adc" =instruction ax8ImmOp }
+ { opcode %15 eq } { "adc" =instruction axImmOp }
+ { opcode %16 eq } { "push %ss (invalid in 64bit)" trivialOp }
+ { opcode %17 eq } { "pop %ss (invalid in 64bit)" trivialOp }
+ { opcode %18 eq } { "sbb" =instruction 0 =dir gpi82Op }
+ { opcode %19 eq } { "sbb" =instruction 0 =dir gpi2Op }
+ { opcode %1A eq } { "sbb" =instruction 1 =dir gpi82Op }
+ { opcode %1B eq } { "sbb" =instruction 1 =dir gpi2Op }
+ { opcode %1C eq } { "sbb" =instruction ax8ImmOp }
+ { opcode %1D eq } { "sbb" =instruction axImmOp }
+ { opcode %1E eq } { "push %ds (invalid in 64bit)" trivialOp }
+ { opcode %1F eq } { "pop %ds (invalid in 64bit)" trivialOp }
+
+ { opcode %20 eq } { "and" =instruction 0 =dir gpi82Op }
+ { opcode %21 eq } { "and" =instruction 0 =dir gpi2Op }
+ { opcode %22 eq } { "and" =instruction 1 =dir gpi82Op }
+ { opcode %23 eq } { "and" =instruction 1 =dir gpi2Op }
+ { opcode %24 eq } { "and" =instruction ax8ImmOp }
+ { opcode %25 eq } { "and" =instruction axImmOp }
+ { opcode %26 eq } { "%es segment prefix (nop in 64bit)" trivialOp }
+ { opcode %27 eq } { "daa (invalid in 64bit)" trivialOp }
+ { opcode %28 eq } { "sub" =instruction 0 =dir gpi82Op }
+ { opcode %29 eq } { "sub" =instruction 0 =dir gpi2Op }
+ { opcode %2A eq } { "sub" =instruction 1 =dir gpi82Op }
+ { opcode %2B eq } { "sub" =instruction 1 =dir gpi2Op }
+ { opcode %2C eq } { "sub" =instruction ax8ImmOp }
+ { opcode %2D eq } { "sub" =instruction axImmOp }
+ { opcode %2E eq } { "%cs segment prefix (nop in 64bit)" trivialOp }
+ { opcode %2F eq } { "das (invalid in 64bit)" trivialOp }
+
+ { opcode %30 eq } { "xor" =instruction 0 =dir gpi82Op }
+ { opcode %31 eq } { "xor" =instruction 0 =dir gpi2Op }
+ { opcode %32 eq } { "xor" =instruction 1 =dir gpi82Op }
+ { opcode %33 eq } { "xor" =instruction 1 =dir gpi2Op }
+ { opcode %34 eq } { "xor" =instruction ax8ImmOp }
+ { opcode %35 eq } { "xor" =instruction axImmOp }
+ { opcode %36 eq } { "%ss segment prefix (nop in 64bit)" trivialOp }
+ { opcode %37 eq } { "aaa (invalid in 64bit)" trivialOp }
+ { opcode %38 eq } { "cmp" =instruction 0 =dir gpi82Op }
+ { opcode %39 eq } { "cmp" =instruction 0 =dir gpi2Op }
+ { opcode %3A eq } { "cmp" =instruction 1 =dir gpi82Op }
+ { opcode %3B eq } { "cmp" =instruction 1 =dir gpi2Op }
+ { opcode %3C eq } { "cmp" =instruction ax8ImmOp }
+ { opcode %3D eq } { "cmp" =instruction axImmOp }
+ { opcode %3E eq } { "%ds segment prefix (nop in 64bit)" trivialOp }
+ { opcode %3F eq } { "aas (invalid in 64bit)" trivialOp }
+
+ { opcode %50 eq } { "push" =instruction 0 rexR 8 mul add =reg popOp }
+ { opcode %51 eq } { "push" =instruction 1 rexR 8 mul add =reg popOp }
+ { opcode %52 eq } { "push" =instruction 2 rexR 8 mul add =reg popOp }
+ { opcode %53 eq } { "push" =instruction 3 rexR 8 mul add =reg popOp }
+ { opcode %54 eq } { "push" =instruction 4 rexR 8 mul add =reg popOp }
+ { opcode %55 eq } { "push" =instruction 5 rexR 8 mul add =reg popOp }
+ { opcode %56 eq } { "push" =instruction 6 rexR 8 mul add =reg popOp }
+ { opcode %57 eq } { "push" =instruction 7 rexR 8 mul add =reg popOp }
+ { opcode %58 eq } { "pop" =instruction 0 rexR 8 mul add =reg popOp }
+ { opcode %59 eq } { "pop" =instruction 1 rexR 8 mul add =reg popOp }
+ { opcode %5A eq } { "pop" =instruction 2 rexR 8 mul add =reg popOp }
+ { opcode %5B eq } { "pop" =instruction 3 rexR 8 mul add =reg popOp }
+ { opcode %5C eq } { "pop" =instruction 4 rexR 8 mul add =reg popOp }
+ { opcode %5D eq } { "pop" =instruction 5 rexR 8 mul add =reg popOp }
+ { opcode %5E eq } { "pop" =instruction 6 rexR 8 mul add =reg popOp }
+ { opcode %5F eq } { "pop" =instruction 7 rexR 8 mul add =reg popOp }
+
+ { opcode %60 eq } { "pusha (invalid in 64bit)" =instruction trivialOp }
+ { opcode %61 eq } { "popa (invalid in 64bit)" =instruction trivialOp }
+ { opcode %62 eq } { "bound (invalid in 64bit)" =instruction trivialOp }
+ # TODO
+
+ { opcode %70 eq } { "jo" =instruction jcc8Op }
+ { opcode %71 eq } { "jno" =instruction jcc8Op }
+ { opcode %72 eq } { "jc" =instruction jcc8Op }
+ { opcode %73 eq } { "jnc" =instruction jcc8Op }
+ { opcode %74 eq } { "jz" =instruction jcc8Op }
+ { opcode %75 eq } { "jnz" =instruction jcc8Op }
+ { opcode %76 eq } { "jbe" =instruction jcc8Op }
+ { opcode %77 eq } { "ja" =instruction jcc8Op }
+ { opcode %78 eq } { "js" =instruction jcc8Op }
+ { opcode %79 eq } { "jns" =instruction jcc8Op }
+ { opcode %7A eq } { "jp" =instruction jcc8Op }
+ { opcode %7B eq } { "jnp" =instruction jcc8Op }
+ { opcode %7C eq } { "jl" =instruction jcc8Op }
+ { opcode %7D eq } { "jge" =instruction jcc8Op }
+ { opcode %7E eq } { "jle" =instruction jcc8Op }
+ { opcode %7F eq } { "jg" =instruction jcc8Op }
+
+ { opcode %80 eq modrmOpcode 7 eq and } { "cmp" =instruction gpi8ImmOp }
+ { opcode %83 eq modrmOpcode 0 eq and } { "add" =instruction gpiImm8Op }
+ { opcode %83 eq modrmOpcode 4 eq and } { "and" =instruction gpiImm8Op }
+ { opcode %83 eq modrmOpcode 5 eq and } { "sub" =instruction gpiImm8Op }
+ { opcode %83 eq modrmOpcode 7 eq and } { "cmp" =instruction gpiImm8Op }
+ { opcode %85 eq } { "test" =instruction 0 =dir gpi2Op }
+ { opcode %89 eq } { "mov" =instruction 0 =dir gpi2Op }
+ { opcode %8B eq } { "mov" =instruction 1 =dir gpi2Op }
+ { opcode %8D eq } { "lea" =instruction 1 =dir gpi2Op }
+ { opcode %B8 eq } { "mov" =instruction 0 rexR 8 mul add =reg movIOp }
+ { opcode %B9 eq } { "mov" =instruction 1 rexR 8 mul add =reg movIOp }
+ { opcode %BA eq } { "mov" =instruction 2 rexR 8 mul add =reg movIOp }
+ { opcode %BB eq } { "mov" =instruction 3 rexR 8 mul add =reg movIOp }
+ { opcode %BC eq } { "mov" =instruction 4 rexR 8 mul add =reg movIOp }
+ { opcode %BD eq } { "mov" =instruction 5 rexR 8 mul add =reg movIOp }
+ { opcode %BE eq } { "mov" =instruction 6 rexR 8 mul add =reg movIOp }
+ { opcode %BF eq } { "mov" =instruction 7 rexR 8 mul add =reg movIOp }
+ { opcode %C1 eq modrmOpcode 5 eq and } { "shr" =instruction gpiImm8Op }
+ { opcode %C1 eq modrmOpcode 7 eq and } { "sar" =instruction gpiImm8Op }
+ { opcode %C3 eq } { "ret" =instruction trivialOp }
+ { opcode %C6 eq modrmOpcode 0 eq and } { "mov" =instruction gpiImm8Op }
+ { opcode %C7 eq modrmOpcode 0 eq and } { "mov" =instruction gpiImmOp }
+ { opcode %C9 eq } { "leave" =instruction trivialOp }
+ { opcode %D1 eq modrmOpcode 5 eq and } { "shr" =instruction gpi1Op }
+ { opcode %D1 eq modrmOpcode 7 eq and } { "sar" =instruction gpi1Op }
+ { opcode %E8 eq } { "call" =instruction callOp }
+ { opcode %E9 eq } { "jmp" =instruction callOp }
+ { opcode %F3 eq } { "repz" =instruction trivialOp }
+ { opcode %F4 eq } { "hlt" =instruction trivialOp }
+ { opcode %FF eq modrmOpcode 2 eq and } { "call" =instruction gpi1Op operandWidth 32 eq { 64 =operandWidth } rep }
+ { opcode %FF eq modrmOpcode 4 eq and } { "jmp" =instruction gpi1Op operandWidth 32 eq { 64 =operandWidth } rep }
+ ] conds
+ > } /fromAddress deffd
+> /decoder defvd
+
+# vim: syn=elymas
diff --git a/samyle/disasm.ey b/samyle/disasm.ey
new file mode 100644
index 0000000..234920d
--- /dev/null
+++ b/samyle/disasm.ey
@@ -0,0 +1,115 @@
+<
+ terminal "$" via $styling "$:" via
+ utils "$$" via
+ locations .cursor "<>" via
+ sys .linux "+" via
+ txt .produce "$>" via
+
+ 0 ==startAddr
+ 0 ==displayRecursion
+
+ <
+ map ==cache
+
+ { # ==addr
+ 1 sub 0 ==i
+ { _ $>hu cache .has not i 15 lt and } { 1 sub i 1 add =i } loop
+ } /prev deffd
+
+ { _ ==addr $>hu ==addrTxt
+ addrTxt cache .has { addrTxt cache * } {
+ addr decoder .fromAddress _ addrTxt cache =[]
+ } ? *
+ }
+ > /instructions defvd /instrs deffd
+
+ {
+ startAddr ==addr
+ 0 ==cursorOnScreen
+
+ $clear
+ 1 ==y
+ { y 20 lt } {
+ addr instrs ==instr
+ <>byte addr eq { y =cursorOnScreen } rep
+
+ 1 y $goto
+ addr $>hu _ locations .names .has {
+ { locations .names * $out } $:red
+ } {
+ $out
+ } ? <>byte addr eq <>column 0 eq and $:reverseIf
+ 30 y $goto
+ 0 instr .length range { ==i
+ { i addr add $$memory $$toHexSave " " cat $out } <>byte addr eq <>column 1 eq and <>elem i eq and $:reverseIf
+ } each
+ 60 y $goto
+ <>byte addr eq <>column 2 eq and {
+ <>elem instr .txtPartSelect -012 $out $reverse $out $normal $out
+ } { instr .txt $out } ? *
+
+ instr .length addr add =addr
+ y 1 add =y
+
+ 1 24 $goto
+ } loop
+
+ cursorOnScreen not { <>byte =startAddr display } rep
+ cursorOnScreen 16 gt { startAddr _ instrs .length add =startAddr display } rep
+ } /draw deffd
+
+ {
+ displayRecursion 1 add =displayRecursion
+ displayRecursion 4 gt { "Deep recursion in display" $err } |draw ? *
+ displayRecursion 1 sub =displayRecursion
+ } /display deffd
+
+ {
+ "" ==currentInput
+ 1 ==running
+ { running } {
+ 1 sys .in .read ==k
+ [
+ { 0 k * 10 eq } { 0 =running }
+ { 1 } { currentInput k _ $out cat =currentInput }
+ ] conds
+ } loop
+ currentInput
+ } /lineInput deffd
+
+ { [
+ { <>column 0 eq } { 0 22 $goto <>byte $>hu $out " => " $out lineInput <>byte $>hu locations .names =[] }
+ ] conds } /substituteElement deffd
+
+ { [
+ { <>column 0 eq } { 1 }
+ { <>column 1 eq } { <>byte instrs .length }
+ { <>column 2 eq } { <>byte instrs .partCount }
+ { 1 } { "??? [elemsInColumn]" $err 1 }
+ ] conds } /elemsInColumn deffd
+
+ { ==k
+ { 0 -01 * } ":" deffst
+
+ [
+ { 0 k * :j eq } { <>byte _ instrs .length add <>gotoByte }
+ { 0 k * :k eq } { <>byte instructions .prev <>gotoByte }
+ { 0 k * :l eq } {
+ <>elem 1 add _ elemsInColumn lt { <>gotoElem } {
+ -- <>column 1 add 2 min <>gotoColumn 0 <>gotoElem
+ } ? *
+ }
+ { 0 k * :h eq } {
+ <>elem 1 sub _ 0 ge { <>gotoElem } {
+ -- <>column 1 sub 0 max _ <>gotoColumn elemsInColumn 1 sub <>gotoElem
+ } ? *
+ }
+ { 0 k * :s eq } |substituteElement
+ ] conds
+ display
+ } /handle deffd
+
+ { _ "" eq |display |handle ? * }
+> -- /disasm deffd
+
+# vim: syn=elymas
diff --git a/samyle/elf.ey b/samyle/elf.ey
new file mode 100644
index 0000000..7b57c94
--- /dev/null
+++ b/samyle/elf.ey
@@ -0,0 +1,117 @@
+<
+ terminal "$" via
+ utils "$$" via $$readMemory "=>" via
+ txt .produce "$>" via
+ sys .linux .ioctl "+" via
+
+ { 1 sub 4096 div 1 add 4096 mul } /roundToPages deffd
+ { 4096 div 4096 mul } /pageStart deffd
+
+ { ==addr
+ [ { addr $$memory _ } { addr 1 add =addr } loop -- ] str .fromArray
+ } /zeroTerminatedString deffd
+
+ {
+ _ dump
+ "\0" cat +ORDONLY 0 +open ==fd
+ fd 0 le { "Could not open file" $err } {
+ fd +fstat -- .size ==size
+ 0 size +PROTREAD +MAPPRIVATE fd 0 +mmap ==addr
+
+ 1 ==keepMapping
+
+ [
+ addr 0 add $$memory 127 eq
+ addr 1 add $$memory 0 "E" * eq
+ addr 2 add $$memory 0 "L" * eq
+ addr 3 add $$memory 0 "F" * eq
+ ] all not { "Not an ELF file" $err } {
+ addr 16 add =>u16 ==fileType
+ addr 24 add =>u64 ==entryPoint
+ addr 32 add =>u64 ==programHeaderOffset
+ addr 40 add =>u64 ==sectionHeaderOffset
+ addr 56 add =>u16 ==programHeaderCount
+ addr 60 add =>u16 ==sectionHeaderCount
+ addr 62 add =>u16 ==sectionNameStringTableIndex
+
+ 1 ==:OBJECT
+ 2 ==:EXECUTABLE
+
+ fileType EXECUTABLE eq {
+ 0 =keepMapping
+
+ 0 programHeaderCount range { ==i
+ addr programHeaderOffset add i 56 mul add ==headerAddr
+ headerAddr =>u16 ==type
+ type 1 eq {
+ headerAddr 8 add =>u64 ==fileOffset
+ headerAddr 16 add =>u64 ==memoryAddress
+ headerAddr 32 add =>u64 ==sizeInFile
+ headerAddr 40 add =>u64 ==sizeInMemory
+
+ memoryAddress pageStart _ ==mappingStart
+ memoryAddress sizeInMemory add mappingStart sub roundToPages
+ +PROTREAD +MAPPRIVATE +MAPFIXED bor fd fileOffset pageStart
+ +mmap 0 lt { ??io.mmap } rep
+ } rep
+ } each
+ } rep
+
+ addr sectionHeaderOffset add sectionNameStringTableIndex 64 mul add 24 add =>u64 ==sectionNameStringTableOffset
+
+ 0 sectionHeaderCount range { ==i
+ addr sectionHeaderOffset add i 64 mul add ==headerAddr
+ headerAddr =>u32 ==nameOffset
+ headerAddr 4 add =>u32 ==type
+ headerAddr 16 add =>u64 ==memoryAddress
+ headerAddr 24 add =>u64 ==fileOffset
+ headerAddr 32 add =>u64 ==size
+ headerAddr 40 add =>u32 ==linkedSection
+
+ fileType EXECUTABLE eq { memoryAddress } { addr fileOffset add } ? * ==sectionAddress
+ sectionAddress 0 neq {
+ addr sectionNameStringTableOffset add nameOffset add zeroTerminatedString
+ sectionAddress $>hu
+ locations .names =[]
+ } rep
+
+ type 11 eq type 2 eq or {
+ addr sectionHeaderOffset add linkedSection 64 mul add 24 add =>u64 ==symbolStringTableOffset
+
+ 0 size 24 div range { ==j
+ addr fileOffset add j 24 mul add =>u32 ==symbolNameOffset
+ addr fileOffset add j 24 mul add 8 add =>u64 ==symbolAddress
+ fileType EXECUTABLE neq { addr symbolAddress add =symbolAddress } rep
+
+ addr symbolStringTableOffset add symbolNameOffset add zeroTerminatedString
+ symbolAddress $>hu
+ locations .names =[]
+ } each
+ } rep
+ } each
+
+ fileType EXECUTABLE eq {
+ "Loaded "
+ programHeaderCount txt .produce .u cat
+ " segments. Entry point at " cat
+ entryPoint txt .produce .hu cat
+ "." cat
+ } {
+ "Loaded "
+ sectionHeaderCount txt .produce .u cat
+ " sections." cat
+ } ? * $info
+
+ [
+ { fileType EXECUTABLE eq } { entryPoint }
+ { ".text" locations .namesReverse .has } { ".text" locations .namesReverse * txt .consume .hu }
+ { 1 } { 0 }
+ ] conds locations .cursor .gotoByte
+ } ? *
+
+ keepMapping not { addr size +munmap -- } rep
+ } ? *
+ } /load deffd
+> /elf defvd
+
+# vim: syn=elymas
diff --git a/samyle/hexedit.ey b/samyle/hexedit.ey
new file mode 100644
index 0000000..170c3eb
--- /dev/null
+++ b/samyle/hexedit.ey
@@ -0,0 +1,34 @@
+<
+ terminal "$" via $styling "$:" via
+ utils "$$" via
+ locations .cursor "<>" via
+
+ 1 neg ==CRAPFILE
+
+ {
+ locations .cursor .byte _ ==addr 16 div 16 mul 128 sub ==base
+
+ $clear
+ 0 16 range { ==y
+ 0 16 range { ==x
+ x 3 mul 1 add y 1 add $goto
+
+ { $$memory $$toHexSave $out } base y 16 mul add x add _ addr eq $:reverseIf
+ } each
+ } each
+ } /display deffd
+
+ { ==k
+ [
+ { 0 k * 106 eq } { <>byte 16 add <>gotoByte }
+ { 0 k * 107 eq } { <>byte 16 sub <>gotoByte }
+ { 0 k * 108 eq } { <>byte 1 add <>gotoByte }
+ { 0 k * 104 eq } { <>byte 1 sub <>gotoByte }
+ ] conds
+ display
+ } /handle deffd
+
+ { _ "" eq |display |handle ? * }
+> -- /hexedit deffd
+
+# vim: syn=elymas
diff --git a/samyle/locations-test.ey b/samyle/locations-test.ey
new file mode 100644
index 0000000..69a4016
--- /dev/null
+++ b/samyle/locations-test.ey
@@ -0,0 +1,6 @@
+"locations.ey" include
+
+/someLabel /someAddr locations .names =[]
+
+/someAddr locations .names * _ dump "someLabel" eq assert
+/someLabel locations .namesReverse * _ dump "someAddr" eq assert
diff --git a/samyle/locations.ey b/samyle/locations.ey
new file mode 100644
index 0000000..503af4e
--- /dev/null
+++ b/samyle/locations.ey
@@ -0,0 +1,24 @@
+<
+ map /names defvd
+
+ <
+ { ==v 0
+ names dom { names * v eq or } each
+ } /has deffd
+ { ==v 0 ==found
+ names dom { _ ==k names * v eq found not and { k 1 =found } rep } each
+ } "#*" deffd
+ > /namesReverse defvd
+
+ <
+ 0 ==byte
+ 0 ==column
+ 0 ==elem
+
+ { =byte } /gotoByte deffd
+ { =column } /gotoColumn deffd
+ { =elem } /gotoElem deffd
+ > /cursor defvd
+> /locations defvd
+
+# vim: syn=elymas
diff --git a/samyle/main.ey b/samyle/main.ey
new file mode 100644
index 0000000..3684bea
--- /dev/null
+++ b/samyle/main.ey
@@ -0,0 +1,33 @@
+"utils.ey" include
+"locations.ey" include
+"terminal.ey" include
+"screens.ey" include
+"elf.ey" include
+"decoder.ey" include
+
+# execute a function while setting the terminal to raw
+{ # =*f
+ sys .linux .ioctl "+" via
+ 0 +tcgets --
+ _ < _ .lflag +ICANON bnot band
+ +ECHO bnot band
+ ==lflag >'
+ { 0 -01 +tcsets -- } -10*3*20*
+} /withRawTerminal deffd
+
+1 ==running
+
+{
+ { running } {
+ 1 sys .in .read ==key
+ key ":" eq {
+ screens .|cmdline screens .enter
+ } {
+ key screens .current
+ } ? *
+ } loop
+} /main deffd
+
+|main withRawTerminal
+
+# vim: syn=elymas
diff --git a/samyle/screens.ey b/samyle/screens.ey
new file mode 100644
index 0000000..4877f42
--- /dev/null
+++ b/samyle/screens.ey
@@ -0,0 +1,15 @@
+<
+ "welcome.ey" include
+ "cmdline.ey" include
+ "hexedit.ey" include
+ "disasm.ey" include
+
+ { |current =last =current "" current } /enter deffd
+ { last =current } /exit deffd
+
+ |welcome _ =*current
+ _ ==last
+ enter
+> /screens defvd
+
+# vim: syn=elymas
diff --git a/samyle/terminal.ey b/samyle/terminal.ey
new file mode 100644
index 0000000..36d9327
--- /dev/null
+++ b/samyle/terminal.ey
@@ -0,0 +1,34 @@
+<
+ sys .out .|writeall '0. /out deffd
+
+ { "\e[2J" out } /clear deffd
+ { "\e[2K" out } /clearLine deffd
+ { "\e[?25l" out } /cursorOff deffd
+ { "\e[?25h" out } /cursorOn deffd
+
+ { "\e[0m" out } /normal deffd
+
+ { deffd }' /defTerminal deffd
+ < { deffd }' > /styling defvd /defStyling deffd
+
+ { ==name ==esc
+ { esc out } name defTerminal
+ { esc out * normal } name defStyling
+ { { esc out * normal } { * } ? * } name "If" cat defStyling
+ } /defStyle deffd
+
+ "\e[1m" /bold defStyle
+ "\e[31m" /red defStyle
+ "\e[32m" /green defStyle
+ "\e[34m" /blue defStyle
+ "\e[7m" /reverse defStyle
+
+ { ==y ==x
+ "\e[" y txt .produce .u cat ";" cat x txt .produce .u cat "H" cat out
+ } /goto deffd
+
+ { ==s clear 40 s len 2 div sub 15 goto "\e[1;31;47;7m" out s out "\e[0m" out 1 sys .in .read -- clear } /err deffd
+ { ==s clear 40 s len 2 div sub 15 goto "\e[1;33;40;7m" out s out "\e[0m" out 1 sys .in .read -- clear } /info deffd
+> /terminal defvd
+
+# vim: syn=elymas
diff --git a/samyle/utils.ey b/samyle/utils.ey
new file mode 100644
index 0000000..d0d5f32
--- /dev/null
+++ b/samyle/utils.ey
@@ -0,0 +1,39 @@
+<
+ sys .linux "+" via
+
+ ".crap\0" +OWRONLY +OCREAT bor +OTRUNC bor 342 +open ==CRAPFILE
+
+ { ==addr
+ CRAPFILE addr 1 +write ==err
+
+ err 0 le { # EFAULT -> address not mapped
+ 1 neg
+ } {
+ addr sys .asm .peek
+ } ? *
+ } '0.0 /memory deffd
+
+ <
+ { # ==addr
+ 0 2 range add memory
+ _ 1 neg eq any { -- ??io.invalid } { 256 math .unbase } ? *
+ } /u16 deffd
+
+ { # ==addr
+ 0 4 range add memory
+ _ 1 neg eq any { -- ??io.invalid } { 256 math .unbase } ? *
+ } /u32 deffd
+
+ { # ==addr
+ 0 8 range add memory
+ _ 1 neg eq any { -- ??io.invalid } { 256 math .unbase } ? *
+ } /u64 deffd
+ > /readMemory defvd
+
+ # CRAPFILE +close
+
+ { _ 16 div -01 16 mod "0123456789ABCDEF" [ -031*21* ] str .fromArray } '0.0 /toHex deffd
+ { _ 1 neg eq { -- "--" } |toHex ? * } '0.0 /toHexSave deffd
+> /utils defvd
+
+# vim: syn=elymas
diff --git a/samyle/welcome.ey b/samyle/welcome.ey
new file mode 100644
index 0000000..3bf41a9
--- /dev/null
+++ b/samyle/welcome.ey
@@ -0,0 +1,16 @@
+<
+ terminal "$" via
+
+ { $clear 0 0 $goto [
+ "Welcome to samyle - the elymas reversing tool\n"
+ "\n"
+ "Many things should work similar to VIm, try :r for example\n"
+ ] $out } /greet deffd
+
+ {
+ --
+ greet
+ }
+> -- /welcome deffd
+
+# vim: syn=elymas