Finally working on we32dis again. Feels good.
This commit is contained in:
parent
88b91ac3df
commit
a3bb5bc81b
|
@ -0,0 +1,54 @@
|
|||
{
|
||||
"movb_acceptance": {
|
||||
"body": [
|
||||
"MOVB &1,%r0",
|
||||
"MOVB &-1,%r1",
|
||||
"MOVB &0xff,%r2",
|
||||
"MOVB &0x1f,%r3",
|
||||
"MOVB $0x100,%r0",
|
||||
"MOVB *$0x200,%r1",
|
||||
"MOVB 5(%r6),%r2",
|
||||
"MOVB *8(%r6),%r3",
|
||||
"MOVB 0xff(%r6),%r4",
|
||||
"MOVB *0xff(%r6),%r4"
|
||||
]
|
||||
},
|
||||
"add_acceptance": {
|
||||
"body": [
|
||||
"ADDW2 &0x100,%r0",
|
||||
"ADDH2 &0x1ff,%r1",
|
||||
"ADDB2 &0xff,%r2"
|
||||
]
|
||||
},
|
||||
"alsw3_acceptance": {
|
||||
"body": [
|
||||
"ALSW3 &1,&1,%r0",
|
||||
"ALSW3 &0x80000000,&1,%r0",
|
||||
"ALSW3 &0x10000000,&1,{sbyte}%r0"
|
||||
]
|
||||
},
|
||||
"andw_acceptance": {
|
||||
"body": [
|
||||
"ANDW2 &0xffff00ff,%r0",
|
||||
"ANDH2 &0xff0f,%r2",
|
||||
"ANDB2 &0x0f,%r3"
|
||||
]
|
||||
},
|
||||
"beb_acceptance": {
|
||||
"body": [
|
||||
"BEB &4",
|
||||
"NOP",
|
||||
"NOP",
|
||||
"BEB &-1"
|
||||
]
|
||||
},
|
||||
"beh_acceptance": {
|
||||
"body": [
|
||||
"BEH &4",
|
||||
"NOP",
|
||||
"NOP",
|
||||
"BEH &-1"
|
||||
]
|
||||
}
|
||||
|
||||
}
|
208
util/we32as.rb
208
util/we32as.rb
|
@ -85,10 +85,6 @@
|
|||
require 'json'
|
||||
require 'optparse'
|
||||
|
||||
#
|
||||
# Monkey patch Numeric with some convenient 2's complement
|
||||
# features.
|
||||
#
|
||||
class Encoder
|
||||
@@registers = {
|
||||
"%r0" => 0,
|
||||
|
@ -163,10 +159,9 @@ class Encoder
|
|||
SUBW3: 0xfc, SUBH3: 0xfe, SUBB: 0xff
|
||||
}
|
||||
|
||||
attr_accessor :pc
|
||||
|
||||
def initialize
|
||||
@pc = 0x2000000
|
||||
def initialize(initial_pc, output_handler)
|
||||
@initial_pc = initial_pc
|
||||
@output_handler = output_handler
|
||||
end
|
||||
|
||||
# Tokenize an instruction and return an array containing 0 to n
|
||||
|
@ -235,10 +230,12 @@ class Encoder
|
|||
end
|
||||
|
||||
def displacement_value(operand_token)
|
||||
md = /^\*?([^\(]+)\(/.match(operand_token)
|
||||
md = /^\*?(-?[^\(]+)\(/.match(operand_token)
|
||||
|
||||
if md
|
||||
parse_number(md[1])
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -454,10 +451,82 @@ class Encoder
|
|||
return bytes
|
||||
end
|
||||
|
||||
def escape(str)
|
||||
str.gsub(/\%/, "\\%")
|
||||
def consume_file(file)
|
||||
test_count = 0
|
||||
|
||||
json_hash = JSON.parse(File.open(file).read)
|
||||
|
||||
@output_handler.print_file_header()
|
||||
|
||||
json_hash.each do |test_name, test_block|
|
||||
|
||||
@pc = @initial_pc
|
||||
|
||||
@output_handler.print_test_header(test_count, test_name)
|
||||
|
||||
test_count += 1
|
||||
|
||||
@output_handler.print_test_setup(@pc, test_block)
|
||||
|
||||
if test_block["body"]
|
||||
test_block["body"].each do |instruction|
|
||||
bytes = to_bytes(instruction)
|
||||
@output_handler.print_instruction(bytes, instruction, @pc)
|
||||
end
|
||||
end
|
||||
|
||||
@output_handler.print_test_teardown(@pc, test_block["body"].size)
|
||||
|
||||
@output_handler.print_execute(test_block)
|
||||
|
||||
@output_handler.print_asserts(test_block)
|
||||
end
|
||||
|
||||
@output_handler.print_file_footer()
|
||||
end
|
||||
end
|
||||
|
||||
class BlitOutputHandler
|
||||
def print_file_header
|
||||
end
|
||||
|
||||
def print_test_header(test_count, test_name)
|
||||
puts "#[test]"
|
||||
puts "fn %s() {" % test_name
|
||||
end
|
||||
|
||||
def print_test_setup(pc, test_block)
|
||||
puts " let program = ["
|
||||
end
|
||||
|
||||
def print_instruction(bytes, instruction, pc)
|
||||
print " "
|
||||
print(bytes.map {|b| "0x%02x," % b }.join(" "))
|
||||
puts " // %s" % instruction
|
||||
end
|
||||
|
||||
def print_test_teardown(pc, test_count)
|
||||
puts " ];"
|
||||
puts " do_with_program(&program, |cpu, mut bus| {"
|
||||
test_count.times do
|
||||
puts " cpu.step(&mut bus);"
|
||||
puts " assert_eq!(0, 0);"
|
||||
end
|
||||
puts " });"
|
||||
puts "}"
|
||||
end
|
||||
|
||||
def print_execute(test_block)
|
||||
end
|
||||
|
||||
def print_asserts(test_block)
|
||||
end
|
||||
|
||||
def print_file_footer
|
||||
end
|
||||
end
|
||||
|
||||
class SimhOutputHandler
|
||||
def print_file_header
|
||||
puts <<EOF
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
@ -475,6 +544,59 @@ on afail goto failure
|
|||
EOF
|
||||
end
|
||||
|
||||
def print_test_header(test_count, test_name)
|
||||
puts ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"
|
||||
puts "ECHO TEST #{test_count}: #{test_name}..."
|
||||
puts
|
||||
end
|
||||
|
||||
def print_test_setup(pc, test_block)
|
||||
puts "; SETUP"
|
||||
|
||||
puts "d pc %04x" % [pc]
|
||||
puts
|
||||
|
||||
if test_block["setup"]
|
||||
test_block["setup"].each do |key, val|
|
||||
puts "d #{key} #{val}"
|
||||
end
|
||||
puts
|
||||
end
|
||||
end
|
||||
|
||||
def print_test_teardown(pc, test_count)
|
||||
end
|
||||
|
||||
def print_instruction(bytes, instruction, pc)
|
||||
if !bytes
|
||||
raise "Unable to assemble instruction: #{instruction}"
|
||||
end
|
||||
|
||||
puts "; #{instruction}"
|
||||
|
||||
bytes.each do |b|
|
||||
puts "dep -b %04x %02x" % [pc, b]
|
||||
pc += 1
|
||||
end
|
||||
end
|
||||
|
||||
def print_execute(test_block)
|
||||
puts
|
||||
puts "; Execute the instruction(s)"
|
||||
puts "STEP %d" % test_block["body"].size
|
||||
puts
|
||||
end
|
||||
|
||||
def print_asserts(test_block)
|
||||
if test_block["asserts"]
|
||||
puts "; ASSERTS"
|
||||
test_block["asserts"].each do |key, val|
|
||||
puts "ASSERT #{key}=#{val}"
|
||||
end
|
||||
puts
|
||||
end
|
||||
end
|
||||
|
||||
def print_file_footer
|
||||
puts <<EOF
|
||||
:success
|
||||
|
@ -493,68 +615,6 @@ show history=1
|
|||
EOF
|
||||
end
|
||||
|
||||
def consume_file(file)
|
||||
test_count = 0
|
||||
|
||||
json_hash = JSON.parse(File.open(file).read)
|
||||
|
||||
print_file_header()
|
||||
|
||||
json_hash.each do |test_name, test_block|
|
||||
|
||||
@pc = 0x2000000
|
||||
|
||||
puts ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"
|
||||
puts "ECHO TEST #{test_count}: #{test_name}..."
|
||||
puts
|
||||
|
||||
test_count += 1
|
||||
|
||||
puts "; SETUP"
|
||||
|
||||
puts "d pc %04x" % [@pc]
|
||||
puts
|
||||
|
||||
if test_block["setup"]
|
||||
test_block["setup"].each do |key, val|
|
||||
puts "d #{key} #{val}"
|
||||
end
|
||||
puts
|
||||
end
|
||||
|
||||
if test_block["body"]
|
||||
test_block["body"].each do |instruction|
|
||||
bytes = to_bytes(instruction)
|
||||
|
||||
if !bytes
|
||||
raise "Unable to assemble instruction: #{instruction}"
|
||||
end
|
||||
|
||||
puts "; #{instruction}"
|
||||
|
||||
bytes.each do |b|
|
||||
puts "dep -b %04x %02x" % [@pc, b]
|
||||
@pc += 1
|
||||
end
|
||||
end
|
||||
puts
|
||||
end
|
||||
|
||||
puts "; Execute the instruction(s)"
|
||||
puts "STEP %d" % test_block["body"].size
|
||||
puts
|
||||
|
||||
if test_block["asserts"]
|
||||
puts "; ASSERTS"
|
||||
test_block["asserts"].each do |key, val|
|
||||
puts "ASSERT #{key}=#{val}"
|
||||
end
|
||||
puts
|
||||
end
|
||||
end
|
||||
|
||||
print_file_footer()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
@ -576,7 +636,7 @@ if __FILE__ == $0
|
|||
|
||||
|
||||
# Start reading in from the input
|
||||
encoder = Encoder.new
|
||||
encoder = Encoder.new(0x2000, BlitOutputHandler.new)
|
||||
|
||||
infile = ARGV[0]
|
||||
|
||||
|
|
|
@ -1,14 +1,10 @@
|
|||
[root]
|
||||
name = "we32dis"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap 2.22.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.9.0"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
|
@ -22,22 +18,36 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "0.8.2"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.22.1"
|
||||
name = "byteorder"
|
||||
version = "1.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.32.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"term_size 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vec_map 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -55,25 +65,46 @@ version = "0.2.21"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "term_size"
|
||||
version = "0.2.3"
|
||||
name = "num-integer"
|
||||
version = "0.1.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.1.0"
|
||||
name = "num-traits"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.1.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.50 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.4"
|
||||
|
@ -81,30 +112,67 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.7.0"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "we32dis"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-build"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6"
|
||||
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||
"checksum atty 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d912da0db7fa85514874458ca3651fe2cddace8d0b0505571dbdcd41ab490159"
|
||||
"checksum bitflags 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1370e9fc2a6ae53aea8b7a5110edbd08836ed87c88736dfabccade1c2b44bff4"
|
||||
"checksum clap 2.22.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e17a4a72ffea176f77d6e2db609c6c919ef221f23862c9915e687fb54d833485"
|
||||
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
||||
"checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d"
|
||||
"checksum chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "45912881121cb26fad7c38c17ba7daa18764771836b34fab7d3fbd93ed633878"
|
||||
"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "88ee81885f9f04bff991e306fea7c1c60a5f0f9e409e99f6b40e3311a3363135"
|
||||
"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
|
||||
"checksum term_size 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "07b6c1ac5b3fffd75073276bca1ceed01f67a28537097a2a9539e116e50fb21a"
|
||||
"checksum unicode-segmentation 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18127285758f0e2c6cf325bb3f3d138a12fee27de4f23e146cd6a179f26c2cf3"
|
||||
"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
|
||||
"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
|
||||
"checksum redox_syscall 0.1.50 (registry+https://github.com/rust-lang/crates.io-index)" = "52ee9a534dc1301776eff45b4fa92d2c39b1d8c3d3357e6eb593e0d795506fc2"
|
||||
"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
|
||||
"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"
|
||||
"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
|
||||
"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f"
|
||||
"checksum vec_map 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8cdc8b93bd0198ed872357fb2e667f7125646b1762f16d60b2c96350d361897"
|
||||
"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
|
||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
name = "we32dis"
|
||||
version = "0.1.0"
|
||||
authors = ["Seth Morabito <web@loomcom.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
clap = "2.22.1"
|
||||
clap = "2.32.0"
|
||||
byteorder = "1"
|
||||
chrono = "0.4.6"
|
||||
bitflags = "1.0.4"
|
|
@ -0,0 +1,242 @@
|
|||
///
|
||||
/// WE32000 COFF File Parsing and Utilities
|
||||
///
|
||||
|
||||
use std::fmt;
|
||||
use std::io::Cursor;
|
||||
use std::io;
|
||||
use std::io::{Read, Seek, SeekFrom};
|
||||
|
||||
use chrono::prelude::*;
|
||||
use chrono::TimeZone;
|
||||
|
||||
use byteorder::{BigEndian, ReadBytesExt};
|
||||
|
||||
// WE32000 without transfer vector
|
||||
const MAGIC_WE32K: u16 = 0x170;
|
||||
|
||||
// WE32000 with transfer vector
|
||||
const MAGIC_WE32K_TV: u16 = 0x171;
|
||||
|
||||
// The optional header (if present) is 28 bytes long
|
||||
const OPT_HEADER_SIZE: u16 = 0x1c;
|
||||
|
||||
bitflags! {
|
||||
pub struct Flags: u16 {
|
||||
// Relocation info stripped from file
|
||||
const REL_STRIPPED = 0x0001;
|
||||
// File is executable (i.e. no unresolved external references)
|
||||
const EXECUTABLE = 0x0002;
|
||||
// Line numbers stripped from file
|
||||
const LINE_NUM_STRIPPED = 0x0004;
|
||||
// Local symbols stripped from file
|
||||
const LSYM_STRIPPED = 0x0010;
|
||||
// This is a minimal object file (".m") output of fextract
|
||||
const MINMAL_OBJECT = 0x0020;
|
||||
// This is a fully bound update file, output of ogen
|
||||
const UPDATE_FILE = 0x0040;
|
||||
// This file has had its bytes swabbed (in names)
|
||||
const SWABBED = 0x0100;
|
||||
// This file has the byte ordering of an AR16WR (e.g. 11/70) machine
|
||||
const BYTES_AR16WR = 0x0200;
|
||||
// This file has the byte ordering of an AR32WR machine (e.g. vax)
|
||||
const BYTES_AR32WR = 0x0400;
|
||||
// This file has the byte ordering of an AR32W machine (e.g. 3b, maxi)
|
||||
const BYTES_AR32W = 0x1000;
|
||||
// File contains "patch" list in optional header
|
||||
const F_PATCH = 0x2000;
|
||||
// (minimal file only) no decision functions for replaced functions
|
||||
const F_NODF = 0x2000;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
pub struct FileHeader {
|
||||
pub magic: u16,
|
||||
pub section_count: u16,
|
||||
pub timestamp: u32,
|
||||
pub symbols_pointer: u32,
|
||||
pub symbol_count: u32,
|
||||
pub opt_header: u16,
|
||||
pub flags: Flags,
|
||||
}
|
||||
|
||||
impl fmt::Debug for FileHeader {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let mut desc = String::new();
|
||||
|
||||
let magic = match self.magic {
|
||||
MAGIC_WE32K => "WE32000 COFF",
|
||||
MAGIC_WE32K_TV => "WE32000 COFF (TV)",
|
||||
_ => "Unknown"
|
||||
};
|
||||
|
||||
desc.push_str(magic);
|
||||
|
||||
if self.flags.contains(Flags::EXECUTABLE) {
|
||||
desc.push_str(" executable");
|
||||
}
|
||||
|
||||
if self.flags.contains(Flags::LSYM_STRIPPED) {
|
||||
desc.push_str(", symbols stripped");
|
||||
} else {
|
||||
desc.push_str(", with symbols");
|
||||
}
|
||||
|
||||
if self.flags.contains(Flags::REL_STRIPPED) {
|
||||
desc.push_str(", relocation info stripped");
|
||||
} else {
|
||||
desc.push_str(", with relocation info");
|
||||
}
|
||||
|
||||
|
||||
write!(f, "{}", desc)
|
||||
}
|
||||
}
|
||||
|
||||
// Only present in the file if the file header's opt_header == 0x1c (28 bytes)
|
||||
pub struct OptionalHeader {
|
||||
pub magic: u16,
|
||||
pub version_stamp: u16,
|
||||
pub text_size: u32,
|
||||
pub dsize: u32,
|
||||
pub bsize: u32,
|
||||
pub entry_point: u32,
|
||||
pub text_start: u32,
|
||||
pub data_start: u32,
|
||||
}
|
||||
|
||||
pub struct SectionHeader {
|
||||
pub name: [u8; 8],
|
||||
pub paddr: u32,
|
||||
pub vaddr: u32,
|
||||
pub size: u32,
|
||||
pub scnptr: u32,
|
||||
pub relptr: u32,
|
||||
pub lnnoptr: u32,
|
||||
pub nreloc: u16,
|
||||
pub nlnno: u16,
|
||||
pub flags: u32,
|
||||
}
|
||||
|
||||
pub struct RelocationEntry {
|
||||
pub vaddr: u32,
|
||||
pub symndx: u32,
|
||||
pub rtype: u16,
|
||||
}
|
||||
|
||||
pub struct Section {
|
||||
pub header: SectionHeader,
|
||||
pub relocation_entries: Vec<RelocationEntry>,
|
||||
}
|
||||
|
||||
pub struct MetaData {
|
||||
pub header: FileHeader,
|
||||
pub timestamp: DateTime<Utc>,
|
||||
pub opt_header: Option<OptionalHeader>,
|
||||
pub sections: Vec<Section>,
|
||||
}
|
||||
|
||||
impl MetaData {
|
||||
pub fn read(cursor: &mut Cursor<&[u8]>) -> io::Result<MetaData> {
|
||||
// FIRST PASS: Pull out File Header, Optional Header (if any),
|
||||
// and Section Headers
|
||||
|
||||
cursor.seek(SeekFrom::Start(0))?;
|
||||
|
||||
let header = FileHeader {
|
||||
magic: cursor.read_u16::<BigEndian>()?,
|
||||
section_count: cursor.read_u16::<BigEndian>()?,
|
||||
timestamp: cursor.read_u32::<BigEndian>()?,
|
||||
symbols_pointer: cursor.read_u32::<BigEndian>()?,
|
||||
symbol_count: cursor.read_u32::<BigEndian>()?,
|
||||
opt_header: cursor.read_u16::<BigEndian>()?,
|
||||
flags: Flags::from_bits_truncate(cursor.read_u16::<BigEndian>()?),
|
||||
};
|
||||
|
||||
let opt_header = if header.opt_header == OPT_HEADER_SIZE {
|
||||
Some(
|
||||
OptionalHeader {
|
||||
magic: cursor.read_u16::<BigEndian>()?,
|
||||
version_stamp: cursor.read_u16::<BigEndian>()?,
|
||||
text_size: cursor.read_u32::<BigEndian>()?,
|
||||
dsize: cursor.read_u32::<BigEndian>()?,
|
||||
bsize: cursor.read_u32::<BigEndian>()?,
|
||||
entry_point: cursor.read_u32::<BigEndian>()?,
|
||||
text_start: cursor.read_u32::<BigEndian>()?,
|
||||
data_start: cursor.read_u32::<BigEndian>()?
|
||||
}
|
||||
)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let mut section_headers: Vec<SectionHeader> = vec!();
|
||||
|
||||
for _ in 0..header.section_count {
|
||||
let mut name: [u8; 8] = [0; 8];
|
||||
cursor.read_exact(&mut name)?;
|
||||
|
||||
let sec_header = SectionHeader {
|
||||
name: name,
|
||||
paddr: cursor.read_u32::<BigEndian>()?,
|
||||
vaddr: cursor.read_u32::<BigEndian>()?,
|
||||
size: cursor.read_u32::<BigEndian>()?,
|
||||
scnptr: cursor.read_u32::<BigEndian>()?,
|
||||
relptr: cursor.read_u32::<BigEndian>()?,
|
||||
lnnoptr: cursor.read_u32::<BigEndian>()?,
|
||||
nreloc: cursor.read_u16::<BigEndian>()?,
|
||||
nlnno: cursor.read_u16::<BigEndian>()?,
|
||||
flags: cursor.read_u32::<BigEndian>()?,
|
||||
};
|
||||
|
||||
section_headers.push(sec_header);
|
||||
}
|
||||
|
||||
// SECOND PASS: Now that we have decoded the section headers,
|
||||
// let's decode the section relocation tables.
|
||||
|
||||
let mut sections: Vec<Section> = vec!();
|
||||
|
||||
for header in section_headers {
|
||||
let mut relocation_entries: Vec<RelocationEntry> = vec!();
|
||||
|
||||
if header.nreloc > 0 {
|
||||
let offset = header.relptr;
|
||||
|
||||
cursor.seek(SeekFrom::Start(u64::from(offset)))?;
|
||||
|
||||
for _ in 0..header.nreloc {
|
||||
let entry = RelocationEntry {
|
||||
vaddr: cursor.read_u32::<BigEndian>()?,
|
||||
symndx: cursor.read_u32::<BigEndian>()?,
|
||||
rtype: cursor.read_u16::<BigEndian>()?,
|
||||
};
|
||||
|
||||
relocation_entries.push(entry);
|
||||
}
|
||||
}
|
||||
|
||||
let section = Section {
|
||||
header,
|
||||
relocation_entries,
|
||||
};
|
||||
|
||||
sections.push(section);
|
||||
}
|
||||
|
||||
// FINAL TOUCHUPS
|
||||
|
||||
let timestamp = Utc.timestamp(i64::from(header.timestamp), 0);
|
||||
|
||||
let metadata = MetaData {
|
||||
header,
|
||||
timestamp,
|
||||
opt_header,
|
||||
sections,
|
||||
};
|
||||
|
||||
Ok(metadata)
|
||||
}
|
||||
}
|
|
@ -1,42 +1,81 @@
|
|||
extern crate clap;
|
||||
#[macro_use] extern crate bitflags;
|
||||
|
||||
use std::error::Error;
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
use std::io::Read;
|
||||
use std::path::Path;
|
||||
use std::vec::Vec;
|
||||
use std::io::Cursor;
|
||||
use std::str;
|
||||
|
||||
use clap::{Arg, App};
|
||||
use we32k::get_opcodes;
|
||||
|
||||
mod we32k;
|
||||
use crate::coff::*;
|
||||
|
||||
fn disassemble(buf: &Vec<u8>) {
|
||||
println!("I'm disassembling a {} byte buffer", buf.len());
|
||||
mod coff;
|
||||
|
||||
let opcodes = get_opcodes();
|
||||
fn name(buf: &[u8]) -> Result<&str, std::str::Utf8Error> {
|
||||
let nul = buf.iter().position( |&c| c == b'\0').unwrap_or(buf.len());
|
||||
str::from_utf8(&buf[0..nul])
|
||||
}
|
||||
|
||||
println!("I have {} opcodes to look at.", opcodes.len());
|
||||
fn disassemble(buf: &[u8]) {
|
||||
let mut cursor = Cursor::new(buf);
|
||||
|
||||
let mut i = 0;
|
||||
let mut op: u16;
|
||||
if let Ok(metadata) = MetaData::read(&mut cursor) {
|
||||
println!("File Header:");
|
||||
println!(" {:?}", metadata.header);
|
||||
println!(" Magic Number: 0x{:04x}", metadata.header.magic);
|
||||
println!(" # Sections: {}", metadata.header.section_count);
|
||||
println!(" Date: {}", metadata.timestamp.to_rfc2822());
|
||||
println!(" Symbols Ptr: 0x{:x}", metadata.header.symbols_pointer);
|
||||
println!(" Symbol Count: {}", metadata.header.symbol_count);
|
||||
println!(" Opt Hdr: {:?}", metadata.header.opt_header == 0x1c);
|
||||
println!(" Flags: 0x{:04x}", metadata.header.flags);
|
||||
|
||||
while i < buf.len() {
|
||||
op = buf[i] as u16;
|
||||
|
||||
// Not all opcodes are one byte. All opcodes starting with
|
||||
// 0x30 are two-bytes long.
|
||||
if op == 0x30 {
|
||||
// Fetch the second byte of the opcode.
|
||||
op = 0x3000 | buf[i + 1] as u16;
|
||||
i = i + 1;
|
||||
if let Some(opt_header) = metadata.opt_header {
|
||||
println!();
|
||||
println!("Optional Header:");
|
||||
println!(" Magic Number: 0x{:04x}", opt_header.magic);
|
||||
println!(" Version Stamp: 0x{:04x}", opt_header.version_stamp);
|
||||
println!(" Text Size: 0x{:x}", opt_header.text_size);
|
||||
println!(" dsize: 0x{:x}", opt_header.dsize);
|
||||
println!(" bsize: 0x{:x}", opt_header.bsize);
|
||||
println!(" Entry Point: 0x{:x}", opt_header.entry_point);
|
||||
println!(" Text Start: 0x{:x}", opt_header.text_start);
|
||||
println!(" Data Start: 0x{:x}", opt_header.data_start);
|
||||
}
|
||||
|
||||
println!("0x{:04x}", op);
|
||||
for section in metadata.sections {
|
||||
|
||||
i += 1;
|
||||
}
|
||||
let header = section.header;
|
||||
|
||||
println!();
|
||||
println!();
|
||||
println!("Section Header:");
|
||||
println!(" Name: {}", name(&header.name).unwrap());
|
||||
println!(" Phys. Addr: 0x{:x}", header.paddr);
|
||||
println!(" Virtual Addr: 0x{:x}", header.vaddr);
|
||||
println!(" Sec. Size: 0x{:x}", header.size);
|
||||
println!(" Data Offset: 0x{:x}", header.scnptr);
|
||||
println!(" Rel. Tab. Offset: 0x{:x}", header.relptr);
|
||||
println!(" Line Num. Offset: 0x{:x}", header.lnnoptr);
|
||||
println!(" Rel. Tab. Entries: {}", header.nreloc);
|
||||
println!(" Line Num. Entries: {}", header.nlnno);
|
||||
println!(" Flags: 0x{:08x}", header.flags);
|
||||
|
||||
// If there is relocation data, let's dump that too.
|
||||
|
||||
if header.nreloc > 0 {
|
||||
println!(" Relocation Table:");
|
||||
|
||||
for (i, entry) in section.relocation_entries.iter().enumerate() {
|
||||
println!(" [{:03}] vaddr=0x{:08x}, symndx={}, type={}",
|
||||
i, entry.vaddr, entry.symndx, entry.rtype);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -62,8 +101,6 @@ fn main() {
|
|||
let path = Path::new(infile);
|
||||
let display = path.display();
|
||||
|
||||
println!("I'm decompiling: {}", display);
|
||||
|
||||
let mut file = match File::open(&path) {
|
||||
Err(why) => panic!("Couldn't open {}: {}", display, why.description()),
|
||||
Ok(file) => file,
|
||||
|
@ -71,9 +108,8 @@ fn main() {
|
|||
|
||||
let mut buf = Vec::new();
|
||||
|
||||
match file.read_to_end(&mut buf) {
|
||||
Err(why) => panic!("Couldn't open {}: {}", display, why.description()),
|
||||
Ok(_) => (),
|
||||
if let Err(why) = file.read_to_end(&mut buf) {
|
||||
panic!("Couldn't open {}: {}", display, why.description())
|
||||
}
|
||||
|
||||
disassemble(&buf);
|
||||
|
|
Loading…
Reference in New Issue