Welcome to Ducky’s documentation!¶
Ducky is a simple virtual CPU/machine simulator, with modular design and interesting features.
About¶
ducky¶
Ducky is a simple virtual CPU/machine simulator, with modular design and interesting features.
Ducky was created for learning purposes, no bigger ambitions. The goal was to experiment with CPU and virtual machine simulation, different instruction sets, and later working FORTH kernel become one of the main goals.
Features¶
Ducky - as in “Ducky, the CPU” - is a 32-bit RISC CPU. Ducky, “the VM”, is a simulator of Ducky CPU, adding few other modules to create the whole virtual machine, with CPUs, peripherals, storages and other components.
RISC instruction set¶
Instruction set was inspired by RISC CPUs, and sticks to LOAD/STORE aproach, with fixed-width instructions.
Memory model¶
Flat, paged, with linear addressing. Main memory consists of memory pages, each page supports simple access control - simple MMU is implemented.
Modular architecture¶
Virtual machine consists of several modules of different classes, and only few of them are necessary (e.g. CPU). Various peripherals are available, and it’s extremely easy to develop your own and plug them in.
SMP support¶
Multiple CPUs with multiple cores per each CPU, with shared memory. Each core can be restricted to its own segment of memory.
Persistent storage¶
Modular persistent storages are available, and accessible by block IO operations, or by mmap-ing storages directly into memory.
Bytecode files¶
Compiled programs are stored in bytecode files that are inspired by ELF executable format. These files consist of common sections (.text
, .data
, ...), symbols, and their content. Assembler (ducky-as
) translates assembler sources into object files, and these are then processed by a linker (ducky-ld
) into the final executable. Both object and executable files use the same format and bytecode for instructions and data.
Snapshots¶
Virtual machine can be suspended, saved, and later restored. This is also useful for debugging purposes, every bit of memory and CPU registers can be investigated.
Debugging support¶
Basic support is included - break points, watch points, stack traces, stepping, snapshots, ...
Tools¶
as
for translating assembler sources to bytecode filesld
for linking bytecode files into the final executableobjdump
for inspection of bytecode filescoredump
for inspection of snapshotsvm
for running virtual machine itselfimg
for converting binaries to images- and
cc
, an experimental C compiler
Planned features¶
FORTH
kernel - basic functionality but at least ANS compliant- network support - it would be awesome to have a network stack available for running programs
- functioning C compiler, with simple C library
- and few others...
Getting started¶
Installing¶
The easy way is to use package:
pip install ducky
Or, you can install Ducky by checking out the sources:
git clone https://github.com/happz/ducky.git
cd ducky
python setup.py
After this, you should have the ducky
module on your path:
>>> import ducky
>>> ducky.__version__
'2.0'
Prerequisites¶
Ducky runs with both Python 2 and 3 - supported versions are 2.7, 3.3, 3.4 and 3.5. There are few other dependencies, installation process (or setup.py
) should take care of them autmatically.
“Hello, world!” tutorial¶
Let’s try out the “Hello, world!” example. It’s a simple program that just prints out the well-known message.
Source code¶
Source is located in examples
directory. If you check it out, it’s a plain and simple assembler:
.include "tty.asm"
.data
.type stack, space
.space 64
.type message, string
.string "Hello, world!"
.text
main:
la sp, &stack
add sp, 64
la r0, &message
call &writesn
hlt 0x00
outb:
; > r0: port
; > r1: byte
outb r0, r1
ret
writesn:
; > r0: string address
; ...
; r0: port
; r1: current byte
; r2: string ptr
push r1
push r2
mov r2, r0
li r0, $TTY_PORT_DATA
.__writesn_loop:
lb r1, r2
bz &.__writesn_write_nl
call &outb
inc r2
j &.__writesn_loop
.__writesn_write_nl:
; \n
li r1, 0x0000000A
call &outb
; \r
li r1, 0x0000000D
call &outb
li r0, 0x00000000
pop r2
pop r1
ret
It’s a little bit more structured that necessary, just for educational purposes.
Binary¶
Virtual machine needs binary (or bytecode, as you wish...) code, and there’s a tool for it:
ducky-as -i examples/hello-world/hello-world.asm -o examples/hello-world/hello-world.o
This command will translate source code to object file, containing instructions for VM and other resources. You can inspect the object file using objdump
tool:
ducky-objdump -i examples/hello-world/hello-world.o -a
This should produce output similar to this one:
[INFO] Input file: examples/hello-world.bin
[INFO]
[INFO] === File header ===
[INFO] Magic: 0xDEAD
[INFO] Version: 1
[INFO] Sections: 4
[INFO]
[INFO] === Sections ===
[INFO]
[INFO] Index Name Type Flags Base Items Size Offset
[INFO] ------- -------- ------- ----------- -------- ------- ------ --------
[INFO] 0 .data DATA RW-- (0x03) 0x000000 14 14 104
[INFO] 1 .text TEXT RWX- (0x07) 0x000100 24 96 118
[INFO] 2 .symtab SYMBOLS ---- (0x00) 0x000200 6 120 214
[INFO] 3 .strings STRINGS ---- (0x00) 0x000000 0 122 334
[INFO]
[INFO] === Symbols ===
[INFO]
[INFO] Name Section Address Type Size File Line Content
[INFO] ---------------------- --------- --------- ------------ ------ ------------------------ ------ ---------------
[INFO] message .data 0x000000 string (2) 14 examples/hello-world.asm 1 "Hello, world!"
[INFO] main .text 0x000100 function (3) 0 examples/hello-world.asm 4
[INFO] outb .text 0x000110 function (3) 0 examples/hello-world.asm 10
[INFO] writesn .text 0x000118 function (3) 0 examples/hello-world.asm 16
[INFO] .__fn_writesn_loop .text 0x00012C function (3) 0 examples/hello-world.asm 27
[INFO] .__fn_writesn_write_nl .text 0x000140 function (3) 0 examples/hello-world.asm 33
[INFO]
[INFO] === Disassemble ==
[INFO]
[INFO] Section .text
[INFO] 0x000100 (0x00000004) li r0, 0x0000
[INFO] 0x000104 (0x0000800D) call 0x0010
[INFO] 0x000108 (0x00000004) li r0, 0x0000
[INFO] 0x00010C (0x0000000B) int 0x0000
[INFO] 0x000110 (0x000000E3) outb r0, r1
[INFO] 0x000114 (0x0000000E) ret
[INFO] 0x000118 (0x000000D4) push r1
[INFO] 0x00011C (0x00000154) push r2
[INFO] 0x000120 (0x00000054) push r0
[INFO] 0x000124 (0x00000095) pop r2
[INFO] 0x000128 (0x00040004) li r0, 0x0100
[INFO] 0x00012C (0x00000842) lb r1, r2
[INFO] 0x000130 (0x00006029) bz 0x000C
[INFO] 0x000134 (0x0FFEC00D) call -0x0028
[INFO] 0x000138 (0x00000096) inc r2
[INFO] 0x00013C (0x0FFF6026) j -0x0014
[INFO] 0x000140 (0x00002844) li r1, 0x000A
[INFO] 0x000144 (0x0FFE400D) call -0x0038
[INFO] 0x000148 (0x00003444) li r1, 0x000D
[INFO] 0x00014C (0x0FFE000D) call -0x0040
[INFO] 0x000150 (0x00000004) li r0, 0x0000
[INFO] 0x000154 (0x00000095) pop r2
[INFO] 0x000158 (0x00000055) pop r1
[INFO] 0x00015C (0x0000000E) ret
[INFO]
You can see internal sections in the object file, list of symbols, and disassembled instructions, with labels replaced by dummy offsets. Offsets in jump instructions make no sense yet because object file is not the finalized binary - yet. For that, there’s another tool:
ducky-ld -i examples/hello-world/hello-world.o -o examples/hello-world/hello-world
This command will take object file (or many of them), and produce one binary by merging code, data and sections in object files, and updates addresses used by instructions to retrieve data and to perform jumps. You can inspect the binary file using objdump
tool, too:
ducky-objdump -i examples/hello-world/hello-world -a
This should produce output very similar to the one you’ve already seen - not much had changed, there was only one object files, only offsets used by call
and j
instructions are now non-zero, meaning they are now pointing to the correct locations.
Running¶
Virtual machine configuration can get quite complicated, so I try to avoid too many command line options, and opt for using configuration files. For this example, there’s one already prepared. Go ahead and try it:
ducky-vm --machine-config=examples/hello-world/hello-world.conf -g
There are two other command line options that deserve some explanation:
-g
- by default, VM prepares itself, and waits for user to pressEnter
to actually start running the loaded binaries. This option tells it to skip “press any key” phase and go ahead.
You should get output similar to this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | 1441740855.82 [INFO] Ducky VM, version 1.0
1441740855.82 [INFO] mm: 16384.0KiB, 16383.5KiB available
1441740855.82 [INFO] hid: basic keyboard controller on [0x0100] as device-1
1441740855.83 [INFO] hid: basic tty on [0x0200] as device-2
1441740855.83 [INFO] hid: basic terminal (device-1, device-2)
1441740855.83 [INFO] snapshot: storage ready, backed by file ducky-snapshot.bin
1441740855.83 [INFO] RTC: time 21:34:15, date: 08/09/15
1441740855.83 [INFO] irq: loading routines from file interrupts
1441740856.02 [INFO] binary: loading from from file examples/hello-world/hello-world
1441740856.02 [INFO] #0:#0: CPU core is up
1441740856.02 [INFO] #0:#0: check-frames: yes
1441740856.02 [INFO] #0:#0: coprocessor: math
1441740856.02 [INFO] #0: CPU is up
Hello, world!
1441740856.04 [INFO] #0:#0: CPU core halted
1441740856.05 [INFO] #0: CPU halted
1441740856.05 [INFO] snapshot: saved in file ducky-snapshot.bin
1441740856.05 [INFO] Halted.
1441740856.05 [INFO]
1441740856.05 [INFO] Exit codes
1441740856.05 [INFO] Core Exit code
1441740856.06 [INFO] ------ -----------
1441740856.06 [INFO] #0:#0 0
1441740856.06 [INFO]
1441740856.06 [INFO] Instruction caches
1441740856.06 [INFO] Core Reads Inserts Hits Misses Prunes
1441740856.06 [INFO] ------ ------- --------- ------ -------- --------
1441740856.06 [INFO] #0:#0 133 34 99 34 0
1441740856.06 [INFO]
1441740856.06 [INFO] Core Ticks
1441740856.06 [INFO] ------ -------
1441740856.06 [INFO] #0:#0 133
1441740856.06 [INFO]
1441740856.06 [INFO] Executed instructions: 133 0.028670 (4639.0223/sec)
1441740856.06 [INFO]
|
And there, on line 15, between all that funny nonsenses, it is! :) The rest of the output are just various notes about loaded binaries, CPU caches, nothing important right now - as I said, terminal is dedicated to VM itself.
Virtual hardware¶
CPU¶
Ducky VM can have multiple CPUs, each with multiple cores. Each core is a 32-bit microprocessor, with 32 32-bit registers, connected to main memory. It is equiped with MMU, and its own instruction cache.
CPU core can work in privileged and unprivileged modes, allowing use of several protected instructions in privileged mode.
Registers¶
- 32 32-bit registers - registers
r0
tor28
are general purpose registers -r30
is reserved, and used as a stack pointer register,SP
- contains address of the last push’ed value on stack -r29
is reserved, and used as a frame pointer register,FP
- contains content ofSP
in time of the lastcall
orint
instruction -r31
is reserved, and used as a instruction pointer register,IP
- contains address of next instruction to be executedflags
register
IP
and flags
registers are protected, and cannot be modified by standard means (push flags; <modify flags>; pop flags
) when CPU is in user mode
Flags register¶
Mask | Flags | Usage |
0x00 | privileged |
If set, CPU runs in privileged mode, and usage of protected instructions is allowed |
0x01 | hwint_allowed |
If set, HW interrupts can be delivered to this core |
0x04 | e |
Set if the last two compared registers were equal |
0x08 | z |
Set if the last arithmetic operation produced zero |
0x10 | o |
Set if the last arithmetic operation overflown |
0x20 | s |
Set if the last arithmetic operation produced negative result |
Instruction set¶
CPU supports multiple instruction set. The default one, ducky, is the main workhorse, suited for general coding, but other instruction sets can exist, e.g. coprocessor may use its own instruction set for its operations.
Design principles¶
- load and store operations are performed by dedicated instructions
- all memory-register transfers work with 32-bit operands, 16-bit and 8-bit operands are handled by special instructions when necessary
- all memory-register transfers work with addresses that are aligned to the size of their operands (1 byte alignment - so no alignment at all - for 8-bit operands)
- in most cases, destination operand is the first one. Exceptions are instructions that work with IO ports.
- when content of a register is changed by an instruction, several flags can be modified subsequently. E.g. when new value of register is zero,
z
flag is set.
Notes on documentation¶
rN
refers to generaly any register, fromr0
up tor28
- special registers are refered to by their common names (e.g.SP
).rA
,rB
refer to the first and the second instruction operand respectively and stand for any register.<value>
means immediate, absolute value. This covers both integers, specified as base 10 or base 16 integers, both positive and negative, and labels and addresses, specified as&label
- when instruction accepts more than one operand type, it is documented using
|
character, e.g.(rA|<value>)
means either register or immediate value
- basic data unit is a word, 4 bytes, 32 bits. Other units are short and byte. Instructions often have variants for different data units, distinguished by a suffix (w for words, s for shorts, and b for single bytes)
- load and store operations are performed by dedicated instructions
- memory-register transfers work with addresses that are aligned to the size of their operands (1 byte alignment - so no alignment at all - for byte operands)
- in most cases, destination operand is the first one. Exceptions are instructions that work with IO ports.
- when content of a register is changed by instruction, several flags can be modified subsequently. E.g. when new value of register is zero,
z
flag is set.
rN
refers to generaly any register, fromr0
up tor28
- special registers are refered to by their common names (e.g.SP
).rA
,rB
refer to the first and the second instruction operand respectively and stand for any register.<value>
means immediate, absolute value. This covers both integers (specified as base 10 or base 16 integers, both positive and negative), and labels and addresses, specified as&label
- when instruction accepts more than one operand type, it is documented using
|
character, e.g.(rA|<value>)
means either register or immediate value
Several instructions transfer control to other routines, with possibility of returning back to previous spot. It is done by creating a stack frame. When stack frame is created, CPU performs these steps:
IP
is pushed onto the stackFP
is pushed onto the stackFP
is loaded with value ofSP
Destroying stack frame - reverting the steps above - effectively transfers control back to the point where the subroutine was called from.
All arithmetic instructions take at least one operand, a register. In case of binary operations, the second operand can be a register, or an immediate value (15 bits wide, sign-extended to 32 bits). The result is always stored in the first operand.
add rA, (rB|<value>)
dec rA
inc rA
mul rA, (rB|<value>)
sub rA, (rB|<value>)
All bitwise operations - with exception of not
- take two operands, a register, and either another register or an immediate value (15 bits wide, sign-extended to 32 bits). The result if always stored in the first operand.
and rA, (rB|<value>)
not rA
or rA, (rB|<value>)
shiftl rA, (rB|<value>)
shiftr rA, (rB|<value>)
xor rA, (rB|<values>)
Branching instructions come in form <inst> (rA|<address>)
. If certain conditions are met, branching instruction will perform jump by adding value of the operand to the current value of PC
(which, when instruction is being executed, points to the next instruction already). If the operand is an immediate address, it is encoded in the instruction as an immediate value (16 bit wide, sign-extended to 32 bits). This limits range of addresses that can be reached using this form of branching instructions.
Branching instructions do not create new stack frame.
j (rA|<value>)
Instruction | Jump when ... |
be
bne
bs
bns
bz
bnz
bo
bno
bg
bge
bl
ble |
e = 1
e = 0
s = 1
s = 0
z = 1
z = 0
o = 1
o = 0
e = 0 and s = 0
e = 1 or s = 0
e = 0 and s = 1
e = 1 or s = 1 |
All conditional setting instructions come in form <inst> rA
. Depending on relevant flags, rA
is set to 1
if condition is evaluated to be true, or to 0
otherwise.
For flags relevant for each instruction, see branching instruction with the same suffix (e.g. setle
evaluates the same flags with the same result as ble
).
Instruction |
sete
setne
setz
setnz
seto
setno
sets
setns
setg
setge
setl
setle |
Two instructions are available for comparing of values. Compare their operands and sets corresponding flags. The second operand can be either a register or an immediate value (15 bits wide).
cmp rA, (rB|<value>)
- immediate value is sign-extended to 32 bits.
cmpu rA, (rB|<value>)
- treat operands as unsigned values, immediate value is zero-extended to 32 bits.
All IO instructions take two operands: port number, specified by register or immediate value, and register.
inw (rA|<port>), rB
- read word from port and store it in rB
ins (rA|<port>), rB
- read short from port and store it in rB
inb (rA|<port>), rB
- read byte from port and store it in rB
outw (rA|<port>), rB
- write value from rB
to port
outs (rA|<port>), rB
- write lower short of rB
to port
outb (rA|<port>), rB
- write lowest byte of rB
to port
If flag hwint_allowed
is unset, no hardware IRQ can be accepted by CPU and stays queued. All queued IRQs will be delivered as soon as flag is set.
cli
- clear hwint
flag
sti
- set hwint
flag
In need of waiting for external events it is possible to suspend CPU until the next IRQ is delivered.
idle
- wait until next IRQ
Any interrupt service routine can be invoked by means of special instruction. When invoked several events take place:
SP
is saved in temporary spaceIP
andSP
are set to values that are stored inIVT
in the corresponding entry- important registers are pushed onto new stack (in this order): old
SP
,flags
- new stack frame is created
- privileged mode is enabled
When routine ends (via retint
), these steps are undone, and content of saved registers is restored.
int (rA|<index>)
retint
- return from interrupt routine
Inter-processor interrupts (IPI
) can be delivered to other processors, via dedicated instruction, similar to int
but specifying CPUID of target core in the first operand.
ipi rA, (rB|<index>)
When routine is called, new stack frame is created, and CPU continues with instructions pointed to by the first operand. For its meaning (and limitations) see Branching instructions.
call (rA|<address>)
ret
nop
- do absolutely nothing
hlt (rA|<value>)
- Halt CPU and set its exit code to specified value.
rst
- reset CPU state. All flags cleared, privileged = 1
, hwint_allowed = 0
, all registers set to 0
mov rA, rB
- copy value of rB
into rA
swp rA, rB
- swap content of two registers
sis <value>
- switch instruction set to a different one
Address operand - {address}
- can be specified in different ways:
rA
- address is stored in registerrA[<offset>]
- address is computed by addition ofrA
andoffset
.offset
can be both positive and negative.fp
andsp
can be also used asrA
.<offset>
is an immediate value, 15 bits wide, sign-extended to 32 bits.
lw rA, {address}
- load word from memory
ls rA, {address}
- load short from memory
lb rA, {address}
- load byte from memory
Instructions for filling registers with values known in compile time.
li rA, <constant>
- load constant
into register. constant
is encoded into instruction as an immediate value (20 bits wide, sign-extended to 32 bits)
liu rA, <constant>
- load constant
into the upper half of register. constant
is encoded into instruction as an immediate value (20 bits wide immediate, only lower 16 bits are used)
la rA, <constant>
- load constant
into the register. constant
is an immediate value (20 bits wide, sign-extended to 32 bits), and is treated as an offset from the current value of PC
- register is loaded with the result of PC + constant
.
cas rA, rB, rC
- read word from address in register rA
. Compare it with value in register rB
- if both are equal, take content of rC
and store it in memory on address rA
, else store memory value in rB
.
Memory¶
Memory model¶
- the full addressable memory is 4 GB, but it is quite unrealistic expectation. I usually stick to 24-bits for addresses, which leads to 16MB of main memory
- memory is organized into pages of 256 bytes - each page can be restricted for read, write and execute operations
Memory layout¶
Interrupt Vector table¶
Interrupt vector table (IVT), located in main memory, is by default located at address 0x00000000
. IVT
address can be set per CPU core. IVT
is 256 bytes long, providing enough space for 64 entries. Typically, lower 32 entries are reserved for hardware interrupts, provided by devices, and upper 32 entries leads to software routines that provide additional functionality for binaries. Each entry has the same layout:
IP - 32 bits |
SP - 32 bits |
When CPU is interrupted - by hardware (device generates interrupt) or software (program executes int
instruction) interrupt - corresponding entry is located in IVT
, using interrupt ID as an index.
Stack¶
- standard LIFO data structure
- grows from higher addresses to lower
- there is no pre-allocated stack, every bit of code needs to prepare its own if it intends to use instructions that operate with stack
- when push’ing value to stack,
SP
is decreased by 4 (size of general register), and then value is stored on this address- each
IVT
provides its own stack pointer
Software¶
Calling convention¶
I use very simple calling convention in my code:
- all arguments are in registers
- first argument in
r0
, second inr1
, ... You get the picture.- if there’s too many arguments, refactor your code or use a stack...
- return value is in
r0
- callee is reponsible for save/restore of registers it’s using, with exception of:
- registers that were used for passing arguments - these are expected to have undefined value when callee returns
r0
if callee returns value back to caller
All virtual interrupt routines, assembler code, any pieces of software I’ve written for this virtual machine follows this calling convention - unless stated otherwise...
Software interrupts¶
Software interrupts provide access to library of common functions, and - in case of virtual interrupts - to internal, complex and otherwise inaccessible resources of virtual machine itself.
For the list for existing interrupts and their numbers, see ducky.irq.IRQList
. However, by the nature of invoking a software interrupt, this list is not carved into a stone. You may easily provide your own IVT
, with entries leading to your own routines, and use e.g. the 33th entry, HALT
, to sing a song.
All values are defined in files in defs/
directory which you can - and should - include into your assembler sources.
BLOCKIO
¶
IVT entry |
33 |
||
Read mode | Write mode | ||
Parameters | r0 |
device id | |
r1 |
bit #0: 0 for read, 1 for write
bit #1: 0 for synchronous, 1 for asynchronous operation |
||
r2 |
block id | src memory address | |
r3 |
dst memory address | block id | |
r4 |
number of blocks | ||
Returns | r0 |
0 for success |
Perform block IO operation - transfer block between memory and storage device. Use the lowest bit of r1
to specify direction:
0
- read mode, blocks are transfered from storage into memory1
- write mode, blocks are tranfered from memory to storage
Current data segment is used for addressing memory locations.
If everything went fine, 0
is returned, any other value means error happened.
IO operation is a blocking action, interrupt will return back to the caller once the IO is finished. Non-blocking (DMA-like) mode is planned but not yet implemented.
This operation is implemented as a virtual interrupt, see ducky.blockio.BlockIOInterrupt
for details.
VMDEBUG
¶
IVT entry |
34 |
|
QUIET mode |
||
Parameters | r0 |
0 |
r1 |
0 for quiet mode, anything else for full mode |
|
Returns | r0 |
0 for success |
VM
interrupt allows control of VM debugging output. Currently, only two levels of verbosity that are available are quiet and full mode. In quiet mode, VM produces no logging output at all.
This interrupt can control level amount of debugging output in case when developer is interested only in debugging only a specific part of his code. Run VM with debugging turned on (-d
option), turn the debugging off at the beggining of the code, and turn it on again at the beggining of the interesting part to get detailed output.
Tools¶
Ducky comes with basic toolchain necessary for development of complex programs. One piece missing is the C cross-compiler with simple C library but this issue will be resolved one day.
Common options¶
All tools accept few common options:
-q, --quiet
¶
Lower verbosity level by one. By default, it is set to info, more quiet levels are warnings, `error and critical.
-v, --verbose
¶
Increase verbosity level by one. By default, it is set to info, more verbose levels is debug. debug level is not available for ducky-vm
unless -d
option is set.
-d, --debug
¶
Set logging level to debug immediately. ducky-vm
also requires this option to even provide any debugging output - it is not possible to emit debug output by setting -v
enough times if -d
is not specified on command-line.
When option takes an address as an argument, address can be specified either using decimal or hexadecimal base. Usually, the absolute address is necessary when option is not binary-aware, yet some options are tied closely to particular binary, such options can also accept name of a symbol. Option handling code will try to find corresponding address in binary’s symbol table. This is valid for both command-line options and configuration files.
as¶
Assembler. Translates assembler files (.asm
) to object files (.o
) - files containing bytecode, symbols information, etc.
Options¶
-i FILE
¶
Take assembly FILE
, and create an object file from its content. It can be specified multiple times, each input file will be processed.
-o FILE
¶
Write resulting object data into FILE
.
This options is optional. If no -o
is specified, ducky-as
will then create output file for each input one by replacing its suffix by .o
. If it is specified, number of -o
options must match the number of -i
options.
-f
¶
When output file exists already, ducky-as
will refuse to overwrite it, unless -f
is set.
-D VAR
¶
Define name, passed to processed assembly sources. User can check for its existence in source by .ifdef
/.ifndef
directives.
-I DIR
¶
Add DIR
to list of directories that are searched for files, when .include
directive asks assembler to process additional source file.
-m, --mmapable-sections
¶
Create object file with sections that can be loaded using mmap()
syscall. This option can save time during VMstartup, when binaries can be simply mmapped into VM’s memory space, but it also creates larger binary files because of the alignment of sections in file.
-w, --writable-sections
By default, .text
and .rodata
sections are read-only. This option lowers this restriction, allowing binary to e.g. modify its own code.
ld¶
Linker. Takes (one or multiple) object files (.o
) and merges them into one, binary, which can be executed by VM.
Options¶
-i FILE
¶
Take object FILE
, and create binary file out of it. It can be specified multiple times, all input files will be processed into one binary file.
-o FILE
¶
Output file.
-f
¶
When output file exists already, ducky-ld
will refuse to overwrite it, unless -f
is set.
--section-base=SECTION=ADDRESS
¶
Linker tries to merge all sections into a binary in a semi-random way - it can be influenced by order of sections in source and object files, and order of input files passed to linker. It is in fact implementation detail and can change in the future. If you need specific section to have its base set to known address, use this option. Be aware that linker may run out of space if you pass conflicting values, or force sections to create too small gaps between each other so other sections would not fit in.
coredump¶
Prints information stored in a saved VM snapshot.
objdump¶
Prints information about object and binary files.
profile¶
Prints information stored in profiling data, created by VM. Used for profiling running binaries.
vm¶
Stand-alone virtual machine - takes binary, configuration files, and other resources, and executes binaries.
VM Configuration file¶
Number of available options can easily get quite high, especially when different devices come into play, and setting all of them on command line is not very clear. To ease this part of VM processes, user can create a configuration file. Syntax is based on Python’s ConfigParser
(or Windows .ini
) configuration files. It consists of sections, setting options for different subsystems (VM, CPUs, ...). You can find few configuration files in examples/
directory.
When option takes an address as an argument, address can be specified either using decimal or hexadecimal base. Usually, the absolute address is necessary when option is not binary-aware, yet some options are tied closely to particular binary, such options can also accept name of a symbol. Option handling code will try to find corresponding address in binary’s symbol table. This is valid for both command-line options and configuration files.
[machine]¶
[memory]¶
[cpu]¶
When set, each CPU core will have its own control coprocessor.
bool
, default yes
When set, CPU cores will check if stack frames were cleaned properly when ret
or iret
is executed.
bool
, default yes
[device-N]¶
Each section starting with device-
tells VM to create virtual device, and provide it to running binaries. Device sections have few options, common for all kinds of devices, and a set of options, specific for each different device or driver.
Device class - arbitrary string, describing family of devices. E.g. I use input
for devices processing user input (e.g. keyboard controllers).
str
, required
If set, master
is superior device, with some responsibilities over its subordinates.
str
, optional
Options¶
--machine-config=PATH
¶
Specify PATH
to VM configuration file. For its content, see VM Configuration file.
--set-option=SECTION:OPTION=VALUE
¶
--add-option=SECTION:OPTION=VALUE
¶
These two options allow user to modify the content of configuration file, by adding of new options or by changing the existing ones.
Lets have (incomplete) config file vm.conf
:
[machine]
cpu = 1
core = 1
[binary-0]
You can use it to run different binaries without having separate config file for each of them, just by telling ducky-vm
to load configuration file, and then change one option:
$ ducky-vm --machine-config=vm.conf --add-option=binary-0:file=<path to binary of your choice>
Similarly, you can modify existing options. Lets have (incomplete) config file vm.conf
:
[machine]
cpus = 1
cores = 1
[binary-0]
file = some/terminal/app
[device-1]
klass = input
driver = ducky.devices.keyboard.KeyboardController
master = device-3
[device-2]
klass = output
driver = ducky.devices.tty.TTY
master = device-3
[device-3]
klass = terminal
driver = ducky.devices.terminal.StandardIOTerminal
input = device-1
output = device-2
Your app
will run using VM’s standard IO streams for input and out. But you may want to start it with a different kind of terminal, e.g. PTY one, and attach to it using screen
:
$ ducky-vm --machine-config=vm.conf --set-option=device-3:driver=ducky.devices.terminal.StandalonePTYTerminal
--enable-device=DEVICE
¶
--disable-device=DEVICE
¶
Shortcuts for --set-option=DEVICE:enabled=yes
and --set-option=DEVICE:enabled=no
respectively.
--poke=ADDRESS:VALUE:LENGTH
¶
poke
option allows modification of VM’s memory after all binaries and resources are loaded, just before the VM starts execution of binaries. It can be used for setting runtime-specific values, e.g. argument for a binary.
Consider a simple binary, running a loop for specified number of iterations:
By default, 10 iterations are hard-coded into binary. If you want to termporarily change number of iterations, it’s not necessary to recompile binary. By default, this binary, being the only one running, would get segment 0x02
, it’s .data
section was mentioned first, therefore its base address will be 0x0000
, leading to loops
having absolute address 0x020000
. Then:
$ ducky-vm --machine-config=vm.conf --poke=0x020000:100:2
will load binary, then modify its .data
section by changing value at address 0x020000
to 100
, which is new number of iterations. Meta variable LENGTH
specifies number of bytes to overwrite by poke
value, and poke
will change exactly LENGTH
bytes - if VALUE
cannot fit into available bits, exceeding bits of VALUE
are masked out, and VALUE
that can fit is zero-extended to use all LENGTH
bytes.
--stdio-console
¶
Enable console terminal with stdin and stdout as its IO streams. User can then enter commands in via the keyboard, while VM and its binaries use e.g. stand-alone pty terminals.
-g, --go-on
¶
By default, ducky-vm
creates a VM and boots it, but before handing the constrol to it, ducky-vm
will ask user to press any key. -g
option tells ducky-vm
to skip this part, and immediately start execution of binaries.
Code Documentation¶
ducky.boot module¶
This file provides necessary code to allow boot up of a virtual machine with the correct program running. This code can provide slightly different environment when compared to real hardware process, since e.g. external files can be mmap-ed into VM’s memory for writing.
-
ducky.boot.
DEFAULT_BOOTLOADER_ADDRESS
= 131072¶ By default, CPU starts executing instructions at this address after boot.
-
ducky.boot.
DEFAULT_HDT_ADDRESS
= 256¶ By default, Hardware Description Table starts at this address after boot.
-
class
ducky.boot.
MMapArea
(ptr, address, size, file_path, offset, pages_start, pages_cnt, flags)[source]¶ Bases:
object
Objects of this class represent one mmaped memory area each, to track this information for later use.
Parameters: - ptr –
mmap object
, as returned by mmap.mmap function. - address (u32_t) – address of the first byte of an area in the memory.
- size (u32_t) – length of the area, in bytes.
- file_path – path to a source file.
- offset (u32_t) – offset of the first byte in the source file.
- pages_start (int) – first page of the area.
- pages_cnt (int) – number of pages in the area.
- flags (mm.binary.SectionFlags) – flags applied to this area.
- ptr –
-
class
ducky.boot.
MMapAreaState
[source]¶ Bases:
ducky.snapshot.SnapshotNode
-
class
ducky.boot.
MMapMemoryPage
(area, *args, **kwargs)[source]¶ Bases:
ducky.mm.ExternalMemoryPage
Memory page backed by an external file that is accessible via
mmap()
call. It’s a part of one of mm.MMapArea instances, and if such area was opened as shared, every change in this page content will affect the content of external file, and vice versa, every change of external file will be reflected in content of this page (if this page lies in affected area).Parameters: area (MMapArea) – area this page belongs to.
-
class
ducky.boot.
ROMLoader
(machine)[source]¶ Bases:
ducky.interfaces.IMachineWorker
-
mmap_area
(file_path, address, size, offset=0, flags=None, shared=False)[source]¶ Assign set of memory pages to mirror external file, mapped into memory.
Parameters: - file_path (string) – path of external file, whose content new area should reflect.
- address (u24) – address where new area should start.
- size (u24) – length of area, in bytes.
- offset (int) – starting point of the area in mmaped file.
- flags (ducky.mm.binary.SectionFlags) – specifies required flags for mmaped pages.
- shared (bool) – if
True
, content of external file is mmaped as shared, i.e. all changes are visible to all processes, not only to the current ducky virtual machine.
Returns: newly created mmap area.
Return type: ducky.mm.MMapArea
Raises: ducky.errors.InvalidResourceError – when
size
is not multiply ofducky.mm.PAGE_SIZE
, or whenaddress
is not multiply ofducky.mm.PAGE_SIZE
, or when any of pages in the affected area is already allocated.
-
setup_hdt
()[source]¶ Initialize memory area that contains HDT.
If VM config file specifies HDT image file, it is loaded, otherwise HDT is constructed for the actual configuration. It is then copied into memory.
Parameters: - machine.hdt-address (u32_t) – Base address of HDT in memory. If not set,
ducky.boot.DEFAULT_HDT_ADDRESS
is used. - machine.hdt-image – HDT image to load. If not set, HDT is constructed for the actual VM’s configuration.
- machine.hdt-address (u32_t) – Base address of HDT in memory. If not set,
-
ducky.config module¶
VM configuration management
-
class
ducky.config.
MachineConfig
(*args, **kwargs)[source]¶ Bases:
ConfigParser.ConfigParser
Contains configuration of the whole VM, and provides methods for parsing, inspection and extending this configuration.
-
add_device
(klass, driver, **kwargs)[source]¶ Add another device to the configuration.
Parameters: - klass (string) – class of the device (
klass
option). - driver (string) – device driver - dot-separated path to class (
driver
option). - kwargs – all keyword arguments will be added to the section as device options.
- klass (string) – class of the device (
-
add_storage
(driver, sid, filepath=None)[source]¶ Add another storage to the configuration.
Parameters: - driver (string) – storage’s driver - dot-separated path to class (
driver
option). - sid (int) – storage’s SID (
sid
options). - filepath (string) – path to backend file, if there’s any (
filepath
option).
- driver (string) – storage’s driver - dot-separated path to class (
-
ducky.console module¶
ducky.cc package¶
Subpackages¶
ducky.cc.passes package¶
Submodules¶
-
class
ducky.cc.passes.ast_codegen.
CodegenVisitor
(*args, **kwargs)[source]¶ Bases:
ducky.cc.passes.ASTVisitor
-
priority
= 1000¶
-
-
class
ducky.cc.passes.ast_visualise.
ASTVisualiseVisitor
(*args, **kwargs)[source]¶ Bases:
ducky.cc.passes.ASTVisitor
Module contents¶
-
class
ducky.cc.passes.
ASTOptVisitor
(logger, *args, **kwargs)[source]¶ Bases:
ducky.cc.passes.ASTVisitor
-
class
ducky.cc.passes.
ASTVisitor
(logger, *args, **kwargs)[source]¶ Bases:
pycparser.c_ast.NodeVisitor
-
priority
= 99¶
-
Submodules¶
ducky.cc.types module¶
-
class
ducky.cc.types.
ArrayType
(item_type, size=None, *args, **kwargs)[source]¶ Bases:
ducky.cc.types.CType
-
class
ducky.cc.types.
CharType
(visitor, decl=None)[source]¶ Bases:
ducky.cc.types.CType
-
class
ducky.cc.types.
FunctionType
(*args, **kwargs)[source]¶ Bases:
ducky.cc.types.CType
-
class
ducky.cc.types.
IntType
(visitor, decl=None)[source]¶ Bases:
ducky.cc.types.CType
-
class
ducky.cc.types.
PointerType
(ptr_to_type, *args, **kwargs)[source]¶ Bases:
ducky.cc.types.CType
-
class
ducky.cc.types.
StructType
(name, *args, **kwargs)[source]¶ Bases:
ducky.cc.types.CType
-
class
ducky.cc.types.
UnsignedCharType
(visitor, decl=None)[source]¶ Bases:
ducky.cc.types.CharType
-
class
ducky.cc.types.
UnsignedIntType
(visitor, decl=None)[source]¶ Bases:
ducky.cc.types.IntType
-
class
ducky.cc.types.
VoidType
(visitor, decl=None)[source]¶ Bases:
ducky.cc.types.CType
Module contents¶
-
class
ducky.cc.
ADD
(*operands)[source]¶ Bases:
ducky.cc.Instruction
-
class
ducky.cc.
AND
(*operands)[source]¶ Bases:
ducky.cc.Instruction
-
class
ducky.cc.
BE
(label)[source]¶ Bases:
ducky.cc.Instruction
-
class
ducky.cc.
BG
(label)[source]¶ Bases:
ducky.cc.Instruction
-
class
ducky.cc.
BGE
(label)[source]¶ Bases:
ducky.cc.Instruction
-
class
ducky.cc.
BL
(label)[source]¶ Bases:
ducky.cc.Instruction
-
class
ducky.cc.
BLE
(label)[source]¶ Bases:
ducky.cc.Instruction
-
class
ducky.cc.
BNE
(label)[source]¶ Bases:
ducky.cc.Instruction
-
class
ducky.cc.
CALL
(label)[source]¶ Bases:
ducky.cc.Instruction
-
class
ducky.cc.
CMP
(left, right)[source]¶ Bases:
ducky.cc.Instruction
-
class
ducky.cc.
ConstantValue
(value)[source]¶ Bases:
ducky.cc.NamedValue
-
class
ducky.cc.
Directive
(directive)[source]¶ Bases:
ducky.cc.Instruction
-
class
ducky.cc.
Expression
(value=None, type=None, klass=<ExpressionClass.RVALUE: 2>)[source]¶ Bases:
object
-
class
ducky.cc.
ExpressionClass
[source]¶ Bases:
enum.Enum
-
LVALUE
= <ExpressionClass.LVALUE: 0>¶
-
MLVALUE
= <ExpressionClass.MLVALUE: 1>¶
-
RVALUE
= <ExpressionClass.RVALUE: 2>¶
-
-
class
ducky.cc.
HLT
(isr)[source]¶ Bases:
ducky.cc.Instruction
-
class
ducky.cc.
INC
(reg)[source]¶ Bases:
ducky.cc.Instruction
-
class
ducky.cc.
INT
(isr)[source]¶ Bases:
ducky.cc.Instruction
-
exception
ducky.cc.
IncompatibleTypesError
(loc, t1, t2)[source]¶ Bases:
ducky.cc.CompilerError
-
class
ducky.cc.
InlineAsm
(code)[source]¶ Bases:
ducky.cc.Instruction
-
exception
ducky.cc.
IsAPointerError
(loc, t)[source]¶ Bases:
ducky.cc.CompilerError
-
class
ducky.cc.
J
(label)[source]¶ Bases:
ducky.cc.Instruction
-
class
ducky.cc.
LA
(reg, value)[source]¶ Bases:
ducky.cc.Instruction
-
class
ducky.cc.
LB
(reg, addr)[source]¶ Bases:
ducky.cc.Instruction
-
class
ducky.cc.
LI
(reg, value)[source]¶ Bases:
ducky.cc.Instruction
-
class
ducky.cc.
LS
(reg, addr)[source]¶ Bases:
ducky.cc.Instruction
-
class
ducky.cc.
LValueExpression
(*args, **kwargs)[source]¶ Bases:
ducky.cc.Expression
-
class
ducky.cc.
LW
(reg, addr)[source]¶ Bases:
ducky.cc.Instruction
-
class
ducky.cc.
MLValueExpression
(*args, **kwargs)[source]¶ Bases:
ducky.cc.Expression
-
class
ducky.cc.
MOV
(*operands)[source]¶ Bases:
ducky.cc.Instruction
-
class
ducky.cc.
MUL
(*operands)[source]¶ Bases:
ducky.cc.Instruction
-
class
ducky.cc.
MemorySlotStorage
(symbol, label)[source]¶ Bases:
ducky.cc.SymbolStorage
-
class
ducky.cc.
MemorySlotValue
(storage)[source]¶ Bases:
ducky.cc.NamedValue
-
class
ducky.cc.
NOT
(*operands)[source]¶ Bases:
ducky.cc.Instruction
-
exception
ducky.cc.
NotAPointerError
(loc, t)[source]¶ Bases:
ducky.cc.CompilerError
-
class
ducky.cc.
OR
(*operands)[source]¶ Bases:
ducky.cc.Instruction
-
class
ducky.cc.
POP
(reg)[source]¶ Bases:
ducky.cc.Instruction
-
class
ducky.cc.
PUSH
(reg)[source]¶ Bases:
ducky.cc.Instruction
-
class
ducky.cc.
RET
[source]¶ Bases:
ducky.cc.Instruction
-
class
ducky.cc.
RValueExpression
(*args, **kwargs)[source]¶ Bases:
ducky.cc.Expression
-
class
ducky.cc.
RegisterMemorySlotValue
(register)[source]¶ Bases:
ducky.cc.NamedValue
-
class
ducky.cc.
RegisterValue
(register)[source]¶ Bases:
ducky.cc.NamedValue
-
class
ducky.cc.
SHL
(reg, ri)[source]¶ Bases:
ducky.cc.Instruction
-
class
ducky.cc.
SHR
(reg, ri)[source]¶ Bases:
ducky.cc.Instruction
-
class
ducky.cc.
STB
(addr, reg)[source]¶ Bases:
ducky.cc.Instruction
-
class
ducky.cc.
STS
(addr, reg)[source]¶ Bases:
ducky.cc.Instruction
-
class
ducky.cc.
STW
(addr, reg)[source]¶ Bases:
ducky.cc.Instruction
-
class
ducky.cc.
SUB
(*operands)[source]¶ Bases:
ducky.cc.Instruction
-
class
ducky.cc.
StackSlotStorage
(symbol, offset)[source]¶ Bases:
ducky.cc.SymbolStorage
-
class
ducky.cc.
StackSlotValue
(storage)[source]¶ Bases:
ducky.cc.NamedValue
-
class
ducky.cc.
StringConstantValue
(value)[source]¶ Bases:
ducky.cc.ConstantValue
-
class
ducky.cc.
Symbol
(visitor, name, decl_type, extern=False, defined=False, const=False)[source]¶ Bases:
object
-
exception
ducky.cc.
SymbolAlreadyDefinedError
(loc, symbol)[source]¶ Bases:
ducky.cc.CompilerError
-
exception
ducky.cc.
SymbolConflictError
(location, msg)[source]¶ Bases:
ducky.cc.CompilerError
-
exception
ducky.cc.
SymbolUndefined
(loc, symbol)[source]¶ Bases:
ducky.cc.CompilerError
-
exception
ducky.cc.
UnableToImplicitCastError
(loc, t1, t2)[source]¶ Bases:
ducky.cc.CompilerError
-
exception
ducky.cc.
UndefinedStructMemberError
(loc, s, m)[source]¶ Bases:
ducky.cc.CompilerError
ducky.cpu package¶
Subpackages¶
ducky.cpu.coprocessor package¶
Submodules¶
-
class
ducky.cpu.coprocessor.control.
ControlCoprocessor
(core)[source]¶ Bases:
ducky.interfaces.ISnapshotable
,ducky.cpu.coprocessor.Coprocessor
-
class
ducky.cpu.coprocessor.control.
ControlRegisters
[source]¶ Bases:
enum.IntEnum
-
CR0
= <ControlRegisters.CR0: 0>¶
-
CR1
= <ControlRegisters.CR1: 1>¶
-
CR2
= <ControlRegisters.CR2: 2>¶
-
CR3
= <ControlRegisters.CR3: 3>¶
-
-
class
ducky.cpu.coprocessor.control.
CoreFlags
[source]¶ Bases:
ducky.util.Flags
-
exception
ducky.cpu.coprocessor.control.
ReadOnlyRegisterError
(r, *args, **kwargs)[source]¶ Bases:
ducky.cpu.CPUException
-
exception
ducky.cpu.coprocessor.control.
WriteOnlyRegisterError
(r, *args, **kwargs)[source]¶ Bases:
ducky.cpu.CPUException
Stack-based coprocessor, providing several arithmetic operations with “long” numbers.
Coprocessor’s instructions operates on a stack of (by default) 8 slots. Operations to move values between math stack and registers/data stack are also available.
In the following documentation several different data types are used:
int
- standard word, 32-bit wide integerlong
- long integer, 64-bit wide
Unless said otherwise, instruction takes its arguments from the stack, removing the values in the process, and pushes the result - if any - back on the stack.
-
class
ducky.cpu.coprocessor.math_copro.
ADDL
(instruction_set)[source]¶ Bases:
ducky.cpu.coprocessor.math_copro.Descriptor_MATH
-
mnemonic
= 'addl'¶
-
opcode
= <MathCoprocessorOpcodes.ADDL: 32>¶
-
-
class
ducky.cpu.coprocessor.math_copro.
DECL
(instruction_set)[source]¶ Bases:
ducky.cpu.coprocessor.math_copro.Descriptor_MATH
Decrement top of the stack by one.
-
mnemonic
= 'decl'¶
-
opcode
= <MathCoprocessorOpcodes.DECL: 31>¶
-
-
class
ducky.cpu.coprocessor.math_copro.
DIVL
(instruction_set)[source]¶ Bases:
ducky.cpu.coprocessor.math_copro.Descriptor_MATH
Divide the value below the top of the math stack by the topmost value.
-
mnemonic
= 'divl'¶
-
opcode
= <MathCoprocessorOpcodes.DIVL: 11>¶
-
-
class
ducky.cpu.coprocessor.math_copro.
DROP
(instruction_set)[source]¶ Bases:
ducky.cpu.coprocessor.math_copro.Descriptor_MATH
-
mnemonic
= 'drop'¶
-
opcode
= <MathCoprocessorOpcodes.DROP: 23>¶
-
-
class
ducky.cpu.coprocessor.math_copro.
DUP
(instruction_set)[source]¶ Bases:
ducky.cpu.coprocessor.math_copro.Descriptor_MATH
-
mnemonic
= 'dup'¶
-
opcode
= <MathCoprocessorOpcodes.DUP: 20>¶
-
-
class
ducky.cpu.coprocessor.math_copro.
DUP2
(instruction_set)[source]¶ Bases:
ducky.cpu.coprocessor.math_copro.Descriptor_MATH
-
mnemonic
= 'dup2'¶
-
opcode
= <MathCoprocessorOpcodes.DUP2: 21>¶
-
-
class
ducky.cpu.coprocessor.math_copro.
Descriptor_MATH
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor_R_R
-
operands
= ''¶
-
-
exception
ducky.cpu.coprocessor.math_copro.
EmptyMathStackError
(*args, **kwargs)[source]¶ Bases:
ducky.cpu.CPUException
Raised when operation expects at least one value on math stack but stack is empty.
-
exception
ducky.cpu.coprocessor.math_copro.
FullMathStackError
(*args, **kwargs)[source]¶ Bases:
ducky.cpu.CPUException
Raised when operation tries to put value on math stack but there is no empty spot available.
-
class
ducky.cpu.coprocessor.math_copro.
INCL
(instruction_set)[source]¶ Bases:
ducky.cpu.coprocessor.math_copro.Descriptor_MATH
Increment top of the stack by one.
-
mnemonic
= 'incl'¶
-
opcode
= <MathCoprocessorOpcodes.INCL: 30>¶
-
-
class
ducky.cpu.coprocessor.math_copro.
LOAD
(instruction_set)[source]¶ Bases:
ducky.cpu.coprocessor.math_copro.Descriptor_MATH
Merge two registers together, and make the result new TOS.
-
mnemonic
= 'load'¶
-
opcode
= <MathCoprocessorOpcodes.LOAD: 9>¶
-
operands
= 'r,r'¶
-
-
class
ducky.cpu.coprocessor.math_copro.
LOADUW
(instruction_set)[source]¶ Bases:
ducky.cpu.coprocessor.math_copro.Descriptor_MATH
Take a value from register, extend it to
long
, and make the result TOS.-
mnemonic
= 'loaduw'¶
-
opcode
= <MathCoprocessorOpcodes.LOADUW: 5>¶
-
operands
= 'r'¶
-
-
class
ducky.cpu.coprocessor.math_copro.
LOADW
(instruction_set)[source]¶ Bases:
ducky.cpu.coprocessor.math_copro.Descriptor_MATH
Take a value from register, extend it to
long
, and make the result TOS.-
mnemonic
= 'loadw'¶
-
opcode
= <MathCoprocessorOpcodes.LOADW: 4>¶
-
operands
= 'r'¶
-
-
class
ducky.cpu.coprocessor.math_copro.
MODL
(instruction_set)[source]¶ Bases:
ducky.cpu.coprocessor.math_copro.Descriptor_MATH
-
mnemonic
= 'modl'¶
-
opcode
= <MathCoprocessorOpcodes.MODL: 12>¶
-
-
class
ducky.cpu.coprocessor.math_copro.
MULL
(instruction_set)[source]¶ Bases:
ducky.cpu.coprocessor.math_copro.Descriptor_MATH
Multiply two top-most numbers on the stack.
-
mnemonic
= 'mull'¶
-
opcode
= <MathCoprocessorOpcodes.MULL: 10>¶
-
-
class
ducky.cpu.coprocessor.math_copro.
MathCoprocessor
(core, *args, **kwargs)[source]¶ Bases:
ducky.interfaces.ISnapshotable
,ducky.cpu.coprocessor.Coprocessor
Coprocessor itself, includes its register set (“math stack”).
Parameters: core (ducky.cpu.CPUCore) – CPU core coprocessor belongs to.
-
class
ducky.cpu.coprocessor.math_copro.
MathCoprocessorInstructionSet
[source]¶ Bases:
ducky.cpu.instructions.InstructionSet
Math coprocessor’s instruction set.
-
instruction_set_id
= 1¶
-
instructions
= [<ducky.cpu.coprocessor.math_copro.ADDL object at 0x7f923a8e83d0>, <ducky.cpu.coprocessor.math_copro.INCL object at 0x7f923a8e8d90>, <ducky.cpu.coprocessor.math_copro.DECL object at 0x7f923a8e81d0>, <ducky.cpu.coprocessor.math_copro.MULL object at 0x7f923a8e8810>, <ducky.cpu.coprocessor.math_copro.DIVL object at 0x7f923a8e8d10>, <ducky.cpu.coprocessor.math_copro.MODL object at 0x7f923a8e8290>, <ducky.cpu.coprocessor.math_copro.UDIVL object at 0x7f923a8e85d0>, <ducky.cpu.coprocessor.math_copro.UMODL object at 0x7f923a8e8cd0>, <ducky.cpu.coprocessor.math_copro.SYMDIVL object at 0x7f923a8e8b90>, <ducky.cpu.coprocessor.math_copro.SYMMODL object at 0x7f923a8e8b10>, <ducky.cpu.coprocessor.math_copro.DUP object at 0x7f923a8e8f90>, <ducky.cpu.coprocessor.math_copro.DUP2 object at 0x7f923a8e8850>, <ducky.cpu.coprocessor.math_copro.SWP object at 0x7f923a974750>, <ducky.cpu.coprocessor.math_copro.DROP object at 0x7f923a974790>, <ducky.cpu.coprocessor.math_copro.PUSHW object at 0x7f923a974d10>, <ducky.cpu.coprocessor.math_copro.SAVEW object at 0x7f923a974950>, <ducky.cpu.coprocessor.math_copro.POPW object at 0x7f923a974f50>, <ducky.cpu.coprocessor.math_copro.LOADW object at 0x7f923a974b90>, <ducky.cpu.coprocessor.math_copro.POPUW object at 0x7f923a9746d0>, <ducky.cpu.coprocessor.math_copro.LOADUW object at 0x7f923a974bd0>, <ducky.cpu.coprocessor.math_copro.PUSH object at 0x7f923a974b10>, <ducky.cpu.coprocessor.math_copro.SAVE object at 0x7f923a974dd0>, <ducky.cpu.coprocessor.math_copro.POP object at 0x7f923a974990>, <ducky.cpu.coprocessor.math_copro.LOAD object at 0x7f923a974cd0>, <ducky.cpu.instructions.SIS object at 0x7f923a974fd0>]¶
-
opcode_desc_map
= {<MathCoprocessorOpcodes.POPW: 0>: <ducky.cpu.coprocessor.math_copro.POPW object at 0x7f923a974f50>, <MathCoprocessorOpcodes.POPUW: 1>: <ducky.cpu.coprocessor.math_copro.POPUW object at 0x7f923a9746d0>, <MathCoprocessorOpcodes.PUSHW: 2>: <ducky.cpu.coprocessor.math_copro.PUSHW object at 0x7f923a974d10>, <MathCoprocessorOpcodes.SAVEW: 3>: <ducky.cpu.coprocessor.math_copro.SAVEW object at 0x7f923a974950>, <MathCoprocessorOpcodes.LOADW: 4>: <ducky.cpu.coprocessor.math_copro.LOADW object at 0x7f923a974b90>, <MathCoprocessorOpcodes.LOADUW: 5>: <ducky.cpu.coprocessor.math_copro.LOADUW object at 0x7f923a974bd0>, <MathCoprocessorOpcodes.POP: 6>: <ducky.cpu.coprocessor.math_copro.POP object at 0x7f923a974990>, <MathCoprocessorOpcodes.SAVE: 7>: <ducky.cpu.coprocessor.math_copro.SAVE object at 0x7f923a974dd0>, <MathCoprocessorOpcodes.PUSH: 8>: <ducky.cpu.coprocessor.math_copro.PUSH object at 0x7f923a974b10>, <MathCoprocessorOpcodes.LOAD: 9>: <ducky.cpu.coprocessor.math_copro.LOAD object at 0x7f923a974cd0>, <MathCoprocessorOpcodes.MULL: 10>: <ducky.cpu.coprocessor.math_copro.MULL object at 0x7f923a8e8810>, <MathCoprocessorOpcodes.DIVL: 11>: <ducky.cpu.coprocessor.math_copro.DIVL object at 0x7f923a8e8d10>, <MathCoprocessorOpcodes.MODL: 12>: <ducky.cpu.coprocessor.math_copro.MODL object at 0x7f923a8e8290>, <MathCoprocessorOpcodes.SYMDIVL: 13>: <ducky.cpu.coprocessor.math_copro.SYMDIVL object at 0x7f923a8e8b90>, <MathCoprocessorOpcodes.SYMMODL: 14>: <ducky.cpu.coprocessor.math_copro.SYMMODL object at 0x7f923a8e8b10>, <MathCoprocessorOpcodes.UDIVL: 15>: <ducky.cpu.coprocessor.math_copro.UDIVL object at 0x7f923a8e85d0>, <MathCoprocessorOpcodes.UMODL: 16>: <ducky.cpu.coprocessor.math_copro.UMODL object at 0x7f923a8e8cd0>, <MathCoprocessorOpcodes.DUP: 20>: <ducky.cpu.coprocessor.math_copro.DUP object at 0x7f923a8e8f90>, <MathCoprocessorOpcodes.DUP2: 21>: <ducky.cpu.coprocessor.math_copro.DUP2 object at 0x7f923a8e8850>, <MathCoprocessorOpcodes.SWP: 22>: <ducky.cpu.coprocessor.math_copro.SWP object at 0x7f923a974750>, <MathCoprocessorOpcodes.DROP: 23>: <ducky.cpu.coprocessor.math_copro.DROP object at 0x7f923a974790>, <MathCoprocessorOpcodes.INCL: 30>: <ducky.cpu.coprocessor.math_copro.INCL object at 0x7f923a8e8d90>, <MathCoprocessorOpcodes.DECL: 31>: <ducky.cpu.coprocessor.math_copro.DECL object at 0x7f923a8e81d0>, <MathCoprocessorOpcodes.ADDL: 32>: <ducky.cpu.coprocessor.math_copro.ADDL object at 0x7f923a8e83d0>, <DuckyOpcodes.SIS: 63>: <ducky.cpu.instructions.SIS object at 0x7f923a974fd0>}¶
-
opcode_encoding_map
= {<MathCoprocessorOpcodes.POPW: 0>: <class 'ducky.cpu.instructions.EncodingR'>, <MathCoprocessorOpcodes.POPUW: 1>: <class 'ducky.cpu.instructions.EncodingR'>, <MathCoprocessorOpcodes.PUSHW: 2>: <class 'ducky.cpu.instructions.EncodingR'>, <MathCoprocessorOpcodes.SAVEW: 3>: <class 'ducky.cpu.instructions.EncodingR'>, <MathCoprocessorOpcodes.LOADW: 4>: <class 'ducky.cpu.instructions.EncodingR'>, <MathCoprocessorOpcodes.LOADUW: 5>: <class 'ducky.cpu.instructions.EncodingR'>, <MathCoprocessorOpcodes.POP: 6>: <class 'ducky.cpu.instructions.EncodingR'>, <MathCoprocessorOpcodes.SAVE: 7>: <class 'ducky.cpu.instructions.EncodingR'>, <MathCoprocessorOpcodes.PUSH: 8>: <class 'ducky.cpu.instructions.EncodingR'>, <MathCoprocessorOpcodes.LOAD: 9>: <class 'ducky.cpu.instructions.EncodingR'>, <MathCoprocessorOpcodes.MULL: 10>: <class 'ducky.cpu.instructions.EncodingR'>, <MathCoprocessorOpcodes.DIVL: 11>: <class 'ducky.cpu.instructions.EncodingR'>, <MathCoprocessorOpcodes.MODL: 12>: <class 'ducky.cpu.instructions.EncodingR'>, <MathCoprocessorOpcodes.SYMDIVL: 13>: <class 'ducky.cpu.instructions.EncodingR'>, <MathCoprocessorOpcodes.SYMMODL: 14>: <class 'ducky.cpu.instructions.EncodingR'>, <MathCoprocessorOpcodes.UDIVL: 15>: <class 'ducky.cpu.instructions.EncodingR'>, <MathCoprocessorOpcodes.UMODL: 16>: <class 'ducky.cpu.instructions.EncodingR'>, <MathCoprocessorOpcodes.DUP: 20>: <class 'ducky.cpu.instructions.EncodingR'>, <MathCoprocessorOpcodes.DUP2: 21>: <class 'ducky.cpu.instructions.EncodingR'>, <MathCoprocessorOpcodes.SWP: 22>: <class 'ducky.cpu.instructions.EncodingR'>, <MathCoprocessorOpcodes.DROP: 23>: <class 'ducky.cpu.instructions.EncodingR'>, <MathCoprocessorOpcodes.INCL: 30>: <class 'ducky.cpu.instructions.EncodingR'>, <MathCoprocessorOpcodes.DECL: 31>: <class 'ducky.cpu.instructions.EncodingR'>, <MathCoprocessorOpcodes.ADDL: 32>: <class 'ducky.cpu.instructions.EncodingR'>, <DuckyOpcodes.SIS: 63>: <class 'ducky.cpu.instructions.EncodingI'>}¶
-
opcodes
¶ alias of
MathCoprocessorOpcodes
-
-
class
ducky.cpu.coprocessor.math_copro.
MathCoprocessorOpcodes
[source]¶ Bases:
enum.IntEnum
Math coprocessor’s instruction opcodes.
-
ADDL
= <MathCoprocessorOpcodes.ADDL: 32>¶
-
DECL
= <MathCoprocessorOpcodes.DECL: 31>¶
-
DIVL
= <MathCoprocessorOpcodes.DIVL: 11>¶
-
DROP
= <MathCoprocessorOpcodes.DROP: 23>¶
-
DUP
= <MathCoprocessorOpcodes.DUP: 20>¶
-
DUP2
= <MathCoprocessorOpcodes.DUP2: 21>¶
-
INCL
= <MathCoprocessorOpcodes.INCL: 30>¶
-
LOAD
= <MathCoprocessorOpcodes.LOAD: 9>¶
-
LOADUW
= <MathCoprocessorOpcodes.LOADUW: 5>¶
-
LOADW
= <MathCoprocessorOpcodes.LOADW: 4>¶
-
MODL
= <MathCoprocessorOpcodes.MODL: 12>¶
-
MULL
= <MathCoprocessorOpcodes.MULL: 10>¶
-
POP
= <MathCoprocessorOpcodes.POP: 6>¶
-
POPUW
= <MathCoprocessorOpcodes.POPUW: 1>¶
-
POPW
= <MathCoprocessorOpcodes.POPW: 0>¶
-
PUSH
= <MathCoprocessorOpcodes.PUSH: 8>¶
-
PUSHW
= <MathCoprocessorOpcodes.PUSHW: 2>¶
-
SAVE
= <MathCoprocessorOpcodes.SAVE: 7>¶
-
SAVEW
= <MathCoprocessorOpcodes.SAVEW: 3>¶
-
SIS
= <MathCoprocessorOpcodes.SIS: 63>¶
-
SWP
= <MathCoprocessorOpcodes.SWP: 22>¶
-
SYMDIVL
= <MathCoprocessorOpcodes.SYMDIVL: 13>¶
-
SYMMODL
= <MathCoprocessorOpcodes.SYMMODL: 14>¶
-
UDIVL
= <MathCoprocessorOpcodes.UDIVL: 15>¶
-
UMODL
= <MathCoprocessorOpcodes.UMODL: 16>¶
-
-
class
ducky.cpu.coprocessor.math_copro.
MathCoprocessorState
[source]¶ Bases:
ducky.snapshot.SnapshotNode
Snapshot node holding the state of math coprocessor.
-
class
ducky.cpu.coprocessor.math_copro.
POP
(instruction_set)[source]¶ Bases:
ducky.cpu.coprocessor.math_copro.Descriptor_MATH
Pop the
long
from data stack, and make it new TOS.-
mnemonic
= 'pop'¶
-
opcode
= <MathCoprocessorOpcodes.POP: 6>¶
-
-
class
ducky.cpu.coprocessor.math_copro.
POPUW
(instruction_set)[source]¶ Bases:
ducky.cpu.coprocessor.math_copro.Descriptor_MATH
Pop the
int``from data stack, extend it to ``long
, and make the result TOS.-
mnemonic
= 'popuw'¶
-
opcode
= <MathCoprocessorOpcodes.POPUW: 1>¶
-
-
class
ducky.cpu.coprocessor.math_copro.
POPW
(instruction_set)[source]¶ Bases:
ducky.cpu.coprocessor.math_copro.Descriptor_MATH
Pop the
int
from data stack, extend it tolong
, and make the result TOS.-
mnemonic
= 'popw'¶
-
opcode
= <MathCoprocessorOpcodes.POPW: 0>¶
-
-
class
ducky.cpu.coprocessor.math_copro.
PUSH
(instruction_set)[source]¶ Bases:
ducky.cpu.coprocessor.math_copro.Descriptor_MATH
Push the TOS on the data stack.
-
mnemonic
= 'push'¶
-
opcode
= <MathCoprocessorOpcodes.PUSH: 8>¶
-
-
class
ducky.cpu.coprocessor.math_copro.
PUSHW
(instruction_set)[source]¶ Bases:
ducky.cpu.coprocessor.math_copro.Descriptor_MATH
Downsize TOS to
int
, and push the result on the data stack.-
mnemonic
= 'pushw'¶
-
opcode
= <MathCoprocessorOpcodes.PUSHW: 2>¶
-
-
class
ducky.cpu.coprocessor.math_copro.
RegisterSet
(core)[source]¶ Bases:
ducky.interfaces.ISnapshotable
Math stack wrapping class. Provides basic push/pop access, and direct access to a top of the stack.
Parameters: core (ducky.cpu.CPUCore) – CPU core registers belong to. -
pop
()[source]¶ Pop the top value from stack and return it.
Raises: ducky.cpu.coprocessor.math_copro.EmptyMathStackError – if there are no values on the stack.
-
push
(v)[source]¶ Push new value on top of the stack.
Raises: ducky.cpu.coprocessor.math_copro.FullMathStackError – if there is no space available on the stack.
-
tos
()[source]¶ Return the top of the stack, without removing it from a stack.
Raises: ducky.cpu.coprocessor.math_copro.EmptyMathStackError – if there are no values on the stack.
-
tos1
()[source]¶ Return the item below the top of the stack, without removing it from a stack.
Raises: ducky.cpu.coprocessor.math_copro.EmptyMathStackError – if there are no values on the stack.
-
-
class
ducky.cpu.coprocessor.math_copro.
SAVE
(instruction_set)[source]¶ Bases:
ducky.cpu.coprocessor.math_copro.Descriptor_MATH
Store TOS in two registers.
-
mnemonic
= 'save'¶
-
opcode
= <MathCoprocessorOpcodes.SAVE: 7>¶
-
operands
= 'r,r'¶
-
-
class
ducky.cpu.coprocessor.math_copro.
SAVEW
(instruction_set)[source]¶ Bases:
ducky.cpu.coprocessor.math_copro.Descriptor_MATH
Downsize TOS to
int
, and store the result in register.-
mnemonic
= 'savew'¶
-
opcode
= <MathCoprocessorOpcodes.SAVEW: 3>¶
-
operands
= 'r'¶
-
-
ducky.cpu.coprocessor.math_copro.
STACK_DEPTH
= 8¶ Number of available spots on the math stack.
-
class
ducky.cpu.coprocessor.math_copro.
SWP
(instruction_set)[source]¶ Bases:
ducky.cpu.coprocessor.math_copro.Descriptor_MATH
-
mnemonic
= 'swp'¶
-
opcode
= <MathCoprocessorOpcodes.SWP: 22>¶
-
-
class
ducky.cpu.coprocessor.math_copro.
SYMDIVL
(instruction_set)[source]¶ Bases:
ducky.cpu.coprocessor.math_copro.Descriptor_MATH
The same operation like
DIVL
but provides symmetric results.-
mnemonic
= 'symdivl'¶
-
opcode
= <MathCoprocessorOpcodes.SYMDIVL: 13>¶
-
-
class
ducky.cpu.coprocessor.math_copro.
SYMMODL
(instruction_set)[source]¶ Bases:
ducky.cpu.coprocessor.math_copro.Descriptor_MATH
-
mnemonic
= 'symmodl'¶
-
opcode
= <MathCoprocessorOpcodes.SYMMODL: 14>¶
-
-
class
ducky.cpu.coprocessor.math_copro.
UDIVL
(instruction_set)[source]¶ Bases:
ducky.cpu.coprocessor.math_copro.Descriptor_MATH
Divide the value below the top of the math stack by the topmost value.
-
mnemonic
= 'udivl'¶
-
opcode
= <MathCoprocessorOpcodes.UDIVL: 15>¶
-
Module contents¶
Coprocessors are intended to extend operations of CPUs. They are optional, and can cover wide range of operations, e.g. floating point arithmetic, encryption, or graphics. They are always attached to a CPU core, and may contain and use internal resources, e.g. their very own register sets, machine’s memory, or their parent’s caches.
Submodules¶
ducky.cpu.assemble module¶
-
class
ducky.cpu.assemble.
AlignSlot
(boundary)[source]¶ Bases:
ducky.cpu.assemble.DataSlot
-
class
ducky.cpu.assemble.
AsciiSlot
[source]¶ Bases:
ducky.cpu.assemble.DataSlot
-
symbol_type
= <SymbolDataTypes.ASCII: 5>¶
-
-
class
ducky.cpu.assemble.
BssSection
(s_name, flags=None, **kwargs)[source]¶ Bases:
ducky.cpu.assemble.Section
-
class
ducky.cpu.assemble.
ByteSlot
[source]¶ Bases:
ducky.cpu.assemble.DataSlot
-
symbol_type
= <SymbolDataTypes.CHAR: 2>¶
-
-
class
ducky.cpu.assemble.
BytesSlot
[source]¶ Bases:
ducky.cpu.assemble.DataSlot
-
symbol_type
= <SymbolDataTypes.ASCII: 5>¶
-
-
class
ducky.cpu.assemble.
CharSlot
[source]¶ Bases:
ducky.cpu.assemble.DataSlot
-
symbol_type
= <SymbolDataTypes.CHAR: 2>¶
-
-
class
ducky.cpu.assemble.
DataSection
(s_name, flags=None, **kwargs)[source]¶ Bases:
ducky.cpu.assemble.Section
-
class
ducky.cpu.assemble.
FunctionSlot
[source]¶ Bases:
ducky.cpu.assemble.DataSlot
-
symbol_type
= <SymbolDataTypes.FUNCTION: 6>¶
-
-
class
ducky.cpu.assemble.
IntSlot
[source]¶ Bases:
ducky.cpu.assemble.DataSlot
-
symbol_type
= <SymbolDataTypes.INT: 0>¶
-
-
class
ducky.cpu.assemble.
RODataSection
(s_name, flags=None, **kwargs)[source]¶ Bases:
ducky.cpu.assemble.Section
-
class
ducky.cpu.assemble.
RelocSection
(s_name, flags=None, **kwargs)[source]¶ Bases:
ducky.cpu.assemble.Section
-
class
ducky.cpu.assemble.
RelocSlot
(name, flags=None, patch_section=None, patch_address=None, patch_offset=None, patch_size=None, patch_add=None)[source]¶ Bases:
object
-
class
ducky.cpu.assemble.
ShortSlot
[source]¶ Bases:
ducky.cpu.assemble.DataSlot
-
symbol_type
= <SymbolDataTypes.SHORT: 1>¶
-
-
class
ducky.cpu.assemble.
SourceLocation
(filename=None, lineno=None, column=None, length=None)[source]¶ Bases:
object
-
class
ducky.cpu.assemble.
SpaceSlot
[source]¶ Bases:
ducky.cpu.assemble.DataSlot
-
symbol_type
= <SymbolDataTypes.ASCII: 5>¶
-
-
class
ducky.cpu.assemble.
StringSlot
[source]¶ Bases:
ducky.cpu.assemble.DataSlot
-
symbol_type
= <SymbolDataTypes.STRING: 4>¶
-
-
class
ducky.cpu.assemble.
SymbolsSection
(s_name, flags=None, **kwargs)[source]¶ Bases:
ducky.cpu.assemble.Section
-
class
ducky.cpu.assemble.
TextSection
(s_name, flags=None, **kwargs)[source]¶ Bases:
ducky.cpu.assemble.Section
ducky.cpu.instructions module¶
-
class
ducky.cpu.instructions.
ADD
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BINOP
-
mnemonic
= 'add'¶
-
opcode
= <DuckyOpcodes.ADD: 28>¶
-
-
class
ducky.cpu.instructions.
AND
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BITOP
-
mnemonic
= 'and'¶
-
opcode
= <DuckyOpcodes.AND: 34>¶
-
-
class
ducky.cpu.instructions.
BE
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BRANCH
-
mnemonic
= 'be'¶
-
-
class
ducky.cpu.instructions.
BG
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BRANCH
-
mnemonic
= 'bg'¶
-
-
class
ducky.cpu.instructions.
BGE
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BRANCH
-
mnemonic
= 'bge'¶
-
-
class
ducky.cpu.instructions.
BL
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BRANCH
-
mnemonic
= 'bl'¶
-
-
class
ducky.cpu.instructions.
BLE
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BRANCH
-
mnemonic
= 'ble'¶
-
-
class
ducky.cpu.instructions.
BNE
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BRANCH
-
mnemonic
= 'bne'¶
-
-
class
ducky.cpu.instructions.
BNO
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BRANCH
-
mnemonic
= 'bno'¶
-
-
class
ducky.cpu.instructions.
BNS
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BRANCH
-
mnemonic
= 'bns'¶
-
-
class
ducky.cpu.instructions.
BNZ
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BRANCH
-
mnemonic
= 'bnz'¶
-
-
class
ducky.cpu.instructions.
BO
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BRANCH
-
mnemonic
= 'bo'¶
-
-
class
ducky.cpu.instructions.
BS
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BRANCH
-
mnemonic
= 'bs'¶
-
-
class
ducky.cpu.instructions.
BZ
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BRANCH
-
mnemonic
= 'bz'¶
-
-
class
ducky.cpu.instructions.
CALL
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._JUMP
-
mnemonic
= 'call'¶
-
opcode
= <DuckyOpcodes.CALL: 15>¶
-
-
class
ducky.cpu.instructions.
CAS
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor
-
mnemonic
= 'cas'¶
-
opcode
= <DuckyOpcodes.CAS: 7>¶
-
operands
= 'r,r,r'¶
-
-
class
ducky.cpu.instructions.
CLI
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor
-
mnemonic
= 'cli'¶
-
opcode
= <DuckyOpcodes.CLI: 17>¶
-
-
class
ducky.cpu.instructions.
CMP
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._CMP
-
mnemonic
= 'cmp'¶
-
opcode
= <DuckyOpcodes.CMP: 47>¶
-
-
class
ducky.cpu.instructions.
CMPU
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._CMP
-
mnemonic
= 'cmpu'¶
-
opcode
= <DuckyOpcodes.CMPU: 48>¶
-
-
class
ducky.cpu.instructions.
CTR
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor_R_R
-
mnemonic
= 'ctr'¶
-
opcode
= <DuckyOpcodes.CTR: 60>¶
-
-
class
ducky.cpu.instructions.
CTW
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor_R_R
-
mnemonic
= 'ctw'¶
-
opcode
= <DuckyOpcodes.CTW: 61>¶
-
-
class
ducky.cpu.instructions.
DEC
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor_R
-
mnemonic
= 'dec'¶
-
opcode
= <DuckyOpcodes.DEC: 27>¶
-
-
class
ducky.cpu.instructions.
DIV
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BINOP
-
mnemonic
= 'div'¶
-
opcode
= <DuckyOpcodes.DIV: 31>¶
-
-
class
ducky.cpu.instructions.
Descriptor
(instruction_set)[source]¶ Bases:
object
-
inst_aligned
= False¶
-
mnemonic
= None¶
-
opcode
= None¶
-
operands
= None¶
-
pattern
= None¶
-
relative_address
= False¶
-
-
class
ducky.cpu.instructions.
Descriptor_I
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor
-
operands
= 'i'¶
-
-
class
ducky.cpu.instructions.
Descriptor_R
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor
-
operands
= 'r'¶
-
-
class
ducky.cpu.instructions.
Descriptor_RI
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor
-
operands
= 'ri'¶
-
-
class
ducky.cpu.instructions.
Descriptor_RI_R
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor
-
operands
= 'ri,r'¶
-
-
class
ducky.cpu.instructions.
Descriptor_R_I
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor
-
operands
= 'r,i'¶
-
-
class
ducky.cpu.instructions.
Descriptor_R_R
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor
-
operands
= 'r,r'¶
-
-
class
ducky.cpu.instructions.
Descriptor_R_RI
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor
-
operands
= 'r,ri'¶
-
-
class
ducky.cpu.instructions.
DuckyInstructionSet
[source]¶ Bases:
ducky.cpu.instructions.InstructionSet
-
instruction_set_id
= 0¶
-
instructions
= [<ducky.cpu.instructions.NOP object at 0x7f923b2a8810>, <ducky.cpu.instructions.INT object at 0x7f923b2a8910>, <ducky.cpu.instructions.IPI object at 0x7f923b2a8950>, <ducky.cpu.instructions.RETINT object at 0x7f923b2a8990>, <ducky.cpu.instructions.CALL object at 0x7f923b2a8a10>, <ducky.cpu.instructions.RET object at 0x7f923b2a8a50>, <ducky.cpu.instructions.CLI object at 0x7f923b2a8ad0>, <ducky.cpu.instructions.STI object at 0x7f923b2a8b50>, <ducky.cpu.instructions.HLT object at 0x7f923b2a8bd0>, <ducky.cpu.instructions.RST object at 0x7f923b2a8c10>, <ducky.cpu.instructions.IDLE object at 0x7f923b2a8c90>, <ducky.cpu.instructions.PUSH object at 0x7f923b2a8d10>, <ducky.cpu.instructions.POP object at 0x7f923b2a8d50>, <ducky.cpu.instructions.INC object at 0x7f923b2a8d90>, <ducky.cpu.instructions.DEC object at 0x7f923b2a8dd0>, <ducky.cpu.instructions.ADD object at 0x7f923b2a8e10>, <ducky.cpu.instructions.SUB object at 0x7f923b2a8e50>, <ducky.cpu.instructions.CMP object at 0x7f923b2a8e90>, <ducky.cpu.instructions.J object at 0x7f923b2a8ed0>, <ducky.cpu.instructions.INW object at 0x7f923b2a8f10>, <ducky.cpu.instructions.INB object at 0x7f923b2a8f50>, <ducky.cpu.instructions.INS object at 0x7f923b2a8f90>, <ducky.cpu.instructions.OUTS object at 0x7f923b2a8fd0>, <ducky.cpu.instructions.OUTW object at 0x7f923b2bf050>, <ducky.cpu.instructions.OUTB object at 0x7f923b2bf090>, <ducky.cpu.instructions.AND object at 0x7f923b2bf0d0>, <ducky.cpu.instructions.OR object at 0x7f923b2bf110>, <ducky.cpu.instructions.XOR object at 0x7f923b2bf150>, <ducky.cpu.instructions.NOT object at 0x7f923b2bf190>, <ducky.cpu.instructions.SHIFTL object at 0x7f923b2bf1d0>, <ducky.cpu.instructions.SHIFTR object at 0x7f923b2bf210>, <ducky.cpu.instructions.LW object at 0x7f923b2bf250>, <ducky.cpu.instructions.LS object at 0x7f923b2bf290>, <ducky.cpu.instructions.LB object at 0x7f923b2bf2d0>, <ducky.cpu.instructions.LI object at 0x7f923b2bf310>, <ducky.cpu.instructions.LIU object at 0x7f923b2bf350>, <ducky.cpu.instructions.LA object at 0x7f923b2bf390>, <ducky.cpu.instructions.STW object at 0x7f923b2bf3d0>, <ducky.cpu.instructions.STS object at 0x7f923b2bf410>, <ducky.cpu.instructions.STB object at 0x7f923b2bf450>, <ducky.cpu.instructions.MOV object at 0x7f923b2bf490>, <ducky.cpu.instructions.SWP object at 0x7f923b2bf4d0>, <ducky.cpu.instructions.MUL object at 0x7f923b2bf510>, <ducky.cpu.instructions.DIV object at 0x7f923b2bf550>, <ducky.cpu.instructions.UDIV object at 0x7f923b2bf590>, <ducky.cpu.instructions.MOD object at 0x7f923b2bf5d0>, <ducky.cpu.instructions.CMPU object at 0x7f923b2bf610>, <ducky.cpu.instructions.CAS object at 0x7f923b2bf650>, <ducky.cpu.instructions.SIS object at 0x7f923b2bf690>, <ducky.cpu.instructions.BE object at 0x7f923b2bf6d0>, <ducky.cpu.instructions.BNE object at 0x7f923b2bf710>, <ducky.cpu.instructions.BZ object at 0x7f923b2bf750>, <ducky.cpu.instructions.BNZ object at 0x7f923b2bf790>, <ducky.cpu.instructions.BO object at 0x7f923b2bf7d0>, <ducky.cpu.instructions.BNO object at 0x7f923b2bf810>, <ducky.cpu.instructions.BS object at 0x7f923b2bf850>, <ducky.cpu.instructions.BNS object at 0x7f923b2bf890>, <ducky.cpu.instructions.BG object at 0x7f923b2bf8d0>, <ducky.cpu.instructions.BGE object at 0x7f923b2bf910>, <ducky.cpu.instructions.BL object at 0x7f923b2bf950>, <ducky.cpu.instructions.BLE object at 0x7f923b2bf990>, <ducky.cpu.instructions.SETE object at 0x7f923b2bf9d0>, <ducky.cpu.instructions.SETNE object at 0x7f923b2bfa10>, <ducky.cpu.instructions.SETZ object at 0x7f923b2bfa50>, <ducky.cpu.instructions.SETNZ object at 0x7f923b2bfa90>, <ducky.cpu.instructions.SETO object at 0x7f923b2bfad0>, <ducky.cpu.instructions.SETNO object at 0x7f923b2bfb10>, <ducky.cpu.instructions.SETS object at 0x7f923b2bfb50>, <ducky.cpu.instructions.SETNS object at 0x7f923b2bfb90>, <ducky.cpu.instructions.SETG object at 0x7f923b2bfbd0>, <ducky.cpu.instructions.SETGE object at 0x7f923b2bfc10>, <ducky.cpu.instructions.SETL object at 0x7f923b2bfc50>, <ducky.cpu.instructions.SETLE object at 0x7f923b2bfc90>, <ducky.cpu.instructions.LPM object at 0x7f923b2bfcd0>, <ducky.cpu.instructions.CTR object at 0x7f923b2bfd50>, <ducky.cpu.instructions.CTW object at 0x7f923b2bfd90>, <ducky.cpu.instructions.FPTC object at 0x7f923b2bfdd0>]¶
-
opcode_desc_map
= {<DuckyOpcodes.NOP: 0>: <ducky.cpu.instructions.NOP object at 0x7f923b2a8810>, <DuckyOpcodes.LW: 1>: <ducky.cpu.instructions.LW object at 0x7f923b2bf250>, <DuckyOpcodes.LS: 2>: <ducky.cpu.instructions.LS object at 0x7f923b2bf290>, <DuckyOpcodes.LB: 3>: <ducky.cpu.instructions.LB object at 0x7f923b2bf2d0>, <DuckyOpcodes.STW: 4>: <ducky.cpu.instructions.STW object at 0x7f923b2bf3d0>, <DuckyOpcodes.STS: 5>: <ducky.cpu.instructions.STS object at 0x7f923b2bf410>, <DuckyOpcodes.STB: 6>: <ducky.cpu.instructions.STB object at 0x7f923b2bf450>, <DuckyOpcodes.CAS: 7>: <ducky.cpu.instructions.CAS object at 0x7f923b2bf650>, <DuckyOpcodes.LA: 8>: <ducky.cpu.instructions.LA object at 0x7f923b2bf390>, <DuckyOpcodes.LI: 9>: <ducky.cpu.instructions.LI object at 0x7f923b2bf310>, <DuckyOpcodes.LIU: 10>: <ducky.cpu.instructions.LIU object at 0x7f923b2bf350>, <DuckyOpcodes.MOV: 11>: <ducky.cpu.instructions.MOV object at 0x7f923b2bf490>, <DuckyOpcodes.SWP: 12>: <ducky.cpu.instructions.SWP object at 0x7f923b2bf4d0>, <DuckyOpcodes.INT: 13>: <ducky.cpu.instructions.INT object at 0x7f923b2a8910>, <DuckyOpcodes.RETINT: 14>: <ducky.cpu.instructions.RETINT object at 0x7f923b2a8990>, <DuckyOpcodes.CALL: 15>: <ducky.cpu.instructions.CALL object at 0x7f923b2a8a10>, <DuckyOpcodes.RET: 16>: <ducky.cpu.instructions.RET object at 0x7f923b2a8a50>, <DuckyOpcodes.CLI: 17>: <ducky.cpu.instructions.CLI object at 0x7f923b2a8ad0>, <DuckyOpcodes.STI: 18>: <ducky.cpu.instructions.STI object at 0x7f923b2a8b50>, <DuckyOpcodes.RST: 19>: <ducky.cpu.instructions.RST object at 0x7f923b2a8c10>, <DuckyOpcodes.HLT: 20>: <ducky.cpu.instructions.HLT object at 0x7f923b2a8bd0>, <DuckyOpcodes.IDLE: 21>: <ducky.cpu.instructions.IDLE object at 0x7f923b2a8c90>, <DuckyOpcodes.LPM: 22>: <ducky.cpu.instructions.LPM object at 0x7f923b2bfcd0>, <DuckyOpcodes.IPI: 23>: <ducky.cpu.instructions.IPI object at 0x7f923b2a8950>, <DuckyOpcodes.PUSH: 24>: <ducky.cpu.instructions.PUSH object at 0x7f923b2a8d10>, <DuckyOpcodes.POP: 25>: <ducky.cpu.instructions.POP object at 0x7f923b2a8d50>, <DuckyOpcodes.INC: 26>: <ducky.cpu.instructions.INC object at 0x7f923b2a8d90>, <DuckyOpcodes.DEC: 27>: <ducky.cpu.instructions.DEC object at 0x7f923b2a8dd0>, <DuckyOpcodes.ADD: 28>: <ducky.cpu.instructions.ADD object at 0x7f923b2a8e10>, <DuckyOpcodes.SUB: 29>: <ducky.cpu.instructions.SUB object at 0x7f923b2a8e50>, <DuckyOpcodes.MUL: 30>: <ducky.cpu.instructions.MUL object at 0x7f923b2bf510>, <DuckyOpcodes.DIV: 31>: <ducky.cpu.instructions.DIV object at 0x7f923b2bf550>, <DuckyOpcodes.UDIV: 32>: <ducky.cpu.instructions.UDIV object at 0x7f923b2bf590>, <DuckyOpcodes.MOD: 33>: <ducky.cpu.instructions.MOD object at 0x7f923b2bf5d0>, <DuckyOpcodes.AND: 34>: <ducky.cpu.instructions.AND object at 0x7f923b2bf0d0>, <DuckyOpcodes.OR: 35>: <ducky.cpu.instructions.OR object at 0x7f923b2bf110>, <DuckyOpcodes.XOR: 36>: <ducky.cpu.instructions.XOR object at 0x7f923b2bf150>, <DuckyOpcodes.NOT: 37>: <ducky.cpu.instructions.NOT object at 0x7f923b2bf190>, <DuckyOpcodes.SHIFTL: 38>: <ducky.cpu.instructions.SHIFTL object at 0x7f923b2bf1d0>, <DuckyOpcodes.SHIFTR: 39>: <ducky.cpu.instructions.SHIFTR object at 0x7f923b2bf210>, <DuckyOpcodes.OUTW: 40>: <ducky.cpu.instructions.OUTW object at 0x7f923b2bf050>, <DuckyOpcodes.OUTS: 41>: <ducky.cpu.instructions.OUTS object at 0x7f923b2a8fd0>, <DuckyOpcodes.OUTB: 42>: <ducky.cpu.instructions.OUTB object at 0x7f923b2bf090>, <DuckyOpcodes.INW: 43>: <ducky.cpu.instructions.INW object at 0x7f923b2a8f10>, <DuckyOpcodes.INS: 44>: <ducky.cpu.instructions.INS object at 0x7f923b2a8f90>, <DuckyOpcodes.INB: 45>: <ducky.cpu.instructions.INB object at 0x7f923b2a8f50>, <DuckyOpcodes.J: 46>: <ducky.cpu.instructions.J object at 0x7f923b2a8ed0>, <DuckyOpcodes.CMP: 47>: <ducky.cpu.instructions.CMP object at 0x7f923b2a8e90>, <DuckyOpcodes.CMPU: 48>: <ducky.cpu.instructions.CMPU object at 0x7f923b2bf610>, <DuckyOpcodes.SET: 49>: <ducky.cpu.instructions.SETLE object at 0x7f923b2bfc90>, <DuckyOpcodes.BRANCH: 50>: <ducky.cpu.instructions.BLE object at 0x7f923b2bf990>, <DuckyOpcodes.CTR: 60>: <ducky.cpu.instructions.CTR object at 0x7f923b2bfd50>, <DuckyOpcodes.CTW: 61>: <ducky.cpu.instructions.CTW object at 0x7f923b2bfd90>, <DuckyOpcodes.FPTC: 62>: <ducky.cpu.instructions.FPTC object at 0x7f923b2bfdd0>, <DuckyOpcodes.SIS: 63>: <ducky.cpu.instructions.SIS object at 0x7f923b2bf690>}¶
-
opcode_encoding_map
= {<DuckyOpcodes.NOP: 0>: <class 'ducky.cpu.instructions.EncodingI'>, <DuckyOpcodes.LW: 1>: <class 'ducky.cpu.instructions.EncodingR'>, <DuckyOpcodes.LS: 2>: <class 'ducky.cpu.instructions.EncodingR'>, <DuckyOpcodes.LB: 3>: <class 'ducky.cpu.instructions.EncodingR'>, <DuckyOpcodes.STW: 4>: <class 'ducky.cpu.instructions.EncodingR'>, <DuckyOpcodes.STS: 5>: <class 'ducky.cpu.instructions.EncodingR'>, <DuckyOpcodes.STB: 6>: <class 'ducky.cpu.instructions.EncodingR'>, <DuckyOpcodes.CAS: 7>: <class 'ducky.cpu.instructions.EncodingA'>, <DuckyOpcodes.LA: 8>: <class 'ducky.cpu.instructions.EncodingI'>, <DuckyOpcodes.LI: 9>: <class 'ducky.cpu.instructions.EncodingI'>, <DuckyOpcodes.LIU: 10>: <class 'ducky.cpu.instructions.EncodingI'>, <DuckyOpcodes.MOV: 11>: <class 'ducky.cpu.instructions.EncodingR'>, <DuckyOpcodes.SWP: 12>: <class 'ducky.cpu.instructions.EncodingR'>, <DuckyOpcodes.INT: 13>: <class 'ducky.cpu.instructions.EncodingI'>, <DuckyOpcodes.RETINT: 14>: <class 'ducky.cpu.instructions.EncodingI'>, <DuckyOpcodes.CALL: 15>: <class 'ducky.cpu.instructions.EncodingI'>, <DuckyOpcodes.RET: 16>: <class 'ducky.cpu.instructions.EncodingI'>, <DuckyOpcodes.CLI: 17>: <class 'ducky.cpu.instructions.EncodingI'>, <DuckyOpcodes.STI: 18>: <class 'ducky.cpu.instructions.EncodingI'>, <DuckyOpcodes.RST: 19>: <class 'ducky.cpu.instructions.EncodingI'>, <DuckyOpcodes.HLT: 20>: <class 'ducky.cpu.instructions.EncodingI'>, <DuckyOpcodes.IDLE: 21>: <class 'ducky.cpu.instructions.EncodingI'>, <DuckyOpcodes.LPM: 22>: <class 'ducky.cpu.instructions.EncodingI'>, <DuckyOpcodes.IPI: 23>: <class 'ducky.cpu.instructions.EncodingR'>, <DuckyOpcodes.PUSH: 24>: <class 'ducky.cpu.instructions.EncodingI'>, <DuckyOpcodes.POP: 25>: <class 'ducky.cpu.instructions.EncodingR'>, <DuckyOpcodes.INC: 26>: <class 'ducky.cpu.instructions.EncodingR'>, <DuckyOpcodes.DEC: 27>: <class 'ducky.cpu.instructions.EncodingR'>, <DuckyOpcodes.ADD: 28>: <class 'ducky.cpu.instructions.EncodingR'>, <DuckyOpcodes.SUB: 29>: <class 'ducky.cpu.instructions.EncodingR'>, <DuckyOpcodes.MUL: 30>: <class 'ducky.cpu.instructions.EncodingR'>, <DuckyOpcodes.DIV: 31>: <class 'ducky.cpu.instructions.EncodingR'>, <DuckyOpcodes.UDIV: 32>: <class 'ducky.cpu.instructions.EncodingR'>, <DuckyOpcodes.MOD: 33>: <class 'ducky.cpu.instructions.EncodingR'>, <DuckyOpcodes.AND: 34>: <class 'ducky.cpu.instructions.EncodingR'>, <DuckyOpcodes.OR: 35>: <class 'ducky.cpu.instructions.EncodingR'>, <DuckyOpcodes.XOR: 36>: <class 'ducky.cpu.instructions.EncodingR'>, <DuckyOpcodes.NOT: 37>: <class 'ducky.cpu.instructions.EncodingR'>, <DuckyOpcodes.SHIFTL: 38>: <class 'ducky.cpu.instructions.EncodingR'>, <DuckyOpcodes.SHIFTR: 39>: <class 'ducky.cpu.instructions.EncodingR'>, <DuckyOpcodes.OUTW: 40>: <class 'ducky.cpu.instructions.EncodingR'>, <DuckyOpcodes.OUTS: 41>: <class 'ducky.cpu.instructions.EncodingR'>, <DuckyOpcodes.OUTB: 42>: <class 'ducky.cpu.instructions.EncodingR'>, <DuckyOpcodes.INW: 43>: <class 'ducky.cpu.instructions.EncodingR'>, <DuckyOpcodes.INS: 44>: <class 'ducky.cpu.instructions.EncodingR'>, <DuckyOpcodes.INB: 45>: <class 'ducky.cpu.instructions.EncodingR'>, <DuckyOpcodes.J: 46>: <class 'ducky.cpu.instructions.EncodingI'>, <DuckyOpcodes.CMP: 47>: <class 'ducky.cpu.instructions.EncodingR'>, <DuckyOpcodes.CMPU: 48>: <class 'ducky.cpu.instructions.EncodingR'>, <DuckyOpcodes.SET: 49>: <class 'ducky.cpu.instructions.EncodingC'>, <DuckyOpcodes.BRANCH: 50>: <class 'ducky.cpu.instructions.EncodingC'>, <DuckyOpcodes.CTR: 60>: <class 'ducky.cpu.instructions.EncodingR'>, <DuckyOpcodes.CTW: 61>: <class 'ducky.cpu.instructions.EncodingR'>, <DuckyOpcodes.FPTC: 62>: <class 'ducky.cpu.instructions.EncodingI'>, <DuckyOpcodes.SIS: 63>: <class 'ducky.cpu.instructions.EncodingI'>}¶
-
opcodes
¶ alias of
DuckyOpcodes
-
-
class
ducky.cpu.instructions.
DuckyOpcodes
[source]¶ Bases:
enum.IntEnum
-
ADD
= <DuckyOpcodes.ADD: 28>¶
-
AND
= <DuckyOpcodes.AND: 34>¶
-
BRANCH
= <DuckyOpcodes.BRANCH: 50>¶
-
CALL
= <DuckyOpcodes.CALL: 15>¶
-
CAS
= <DuckyOpcodes.CAS: 7>¶
-
CLI
= <DuckyOpcodes.CLI: 17>¶
-
CMP
= <DuckyOpcodes.CMP: 47>¶
-
CMPU
= <DuckyOpcodes.CMPU: 48>¶
-
CTR
= <DuckyOpcodes.CTR: 60>¶
-
CTW
= <DuckyOpcodes.CTW: 61>¶
-
DEC
= <DuckyOpcodes.DEC: 27>¶
-
DIV
= <DuckyOpcodes.DIV: 31>¶
-
FPTC
= <DuckyOpcodes.FPTC: 62>¶
-
HLT
= <DuckyOpcodes.HLT: 20>¶
-
IDLE
= <DuckyOpcodes.IDLE: 21>¶
-
INB
= <DuckyOpcodes.INB: 45>¶
-
INC
= <DuckyOpcodes.INC: 26>¶
-
INS
= <DuckyOpcodes.INS: 44>¶
-
INT
= <DuckyOpcodes.INT: 13>¶
-
INW
= <DuckyOpcodes.INW: 43>¶
-
IPI
= <DuckyOpcodes.IPI: 23>¶
-
J
= <DuckyOpcodes.J: 46>¶
-
LA
= <DuckyOpcodes.LA: 8>¶
-
LB
= <DuckyOpcodes.LB: 3>¶
-
LI
= <DuckyOpcodes.LI: 9>¶
-
LIU
= <DuckyOpcodes.LIU: 10>¶
-
LPM
= <DuckyOpcodes.LPM: 22>¶
-
LS
= <DuckyOpcodes.LS: 2>¶
-
LW
= <DuckyOpcodes.LW: 1>¶
-
MOD
= <DuckyOpcodes.MOD: 33>¶
-
MOV
= <DuckyOpcodes.MOV: 11>¶
-
MUL
= <DuckyOpcodes.MUL: 30>¶
-
NOP
= <DuckyOpcodes.NOP: 0>¶
-
NOT
= <DuckyOpcodes.NOT: 37>¶
-
OR
= <DuckyOpcodes.OR: 35>¶
-
OUTB
= <DuckyOpcodes.OUTB: 42>¶
-
OUTS
= <DuckyOpcodes.OUTS: 41>¶
-
OUTW
= <DuckyOpcodes.OUTW: 40>¶
-
POP
= <DuckyOpcodes.POP: 25>¶
-
PUSH
= <DuckyOpcodes.PUSH: 24>¶
-
RET
= <DuckyOpcodes.RET: 16>¶
-
RETINT
= <DuckyOpcodes.RETINT: 14>¶
-
RST
= <DuckyOpcodes.RST: 19>¶
-
SET
= <DuckyOpcodes.SET: 49>¶
-
SHIFTL
= <DuckyOpcodes.SHIFTL: 38>¶
-
SHIFTR
= <DuckyOpcodes.SHIFTR: 39>¶
-
SIS
= <DuckyOpcodes.SIS: 63>¶
-
STB
= <DuckyOpcodes.STB: 6>¶
-
STI
= <DuckyOpcodes.STI: 18>¶
-
STS
= <DuckyOpcodes.STS: 5>¶
-
STW
= <DuckyOpcodes.STW: 4>¶
-
SUB
= <DuckyOpcodes.SUB: 29>¶
-
SWP
= <DuckyOpcodes.SWP: 12>¶
-
UDIV
= <DuckyOpcodes.UDIV: 32>¶
-
XOR
= <DuckyOpcodes.XOR: 36>¶
-
-
ducky.cpu.instructions.
ENCODE
(logger, buffer, inst, field, size, value, raise_on_large_value=False)[source]¶
-
class
ducky.cpu.instructions.
EncodingA
[source]¶ Bases:
_ctypes.Structure
-
opcode
¶ Structure/Union member
-
reg1
¶ Structure/Union member
-
reg2
¶ Structure/Union member
-
reg3
¶ Structure/Union member
-
-
class
ducky.cpu.instructions.
EncodingC
[source]¶ Bases:
_ctypes.Structure
-
flag
¶ Structure/Union member
-
immediate
¶ Structure/Union member
-
immediate_flag
¶ Structure/Union member
-
opcode
¶ Structure/Union member
-
reg
¶ Structure/Union member
-
value
¶ Structure/Union member
-
-
class
ducky.cpu.instructions.
EncodingI
[source]¶ Bases:
_ctypes.Structure
-
immediate
¶ Structure/Union member
-
immediate_flag
¶ Structure/Union member
-
opcode
¶ Structure/Union member
-
reg
¶ Structure/Union member
-
-
class
ducky.cpu.instructions.
EncodingR
[source]¶ Bases:
_ctypes.Structure
-
immediate
¶ Structure/Union member
-
immediate_flag
¶ Structure/Union member
-
opcode
¶ Structure/Union member
-
reg1
¶ Structure/Union member
-
reg2
¶ Structure/Union member
-
-
class
ducky.cpu.instructions.
FPTC
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor
-
mnemonic
= 'fptc'¶
-
opcode
= <DuckyOpcodes.FPTC: 62>¶
-
-
class
ducky.cpu.instructions.
HLT
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor_RI
-
mnemonic
= 'hlt'¶
-
opcode
= <DuckyOpcodes.HLT: 20>¶
-
-
class
ducky.cpu.instructions.
IDLE
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor
-
mnemonic
= 'idle'¶
-
opcode
= <DuckyOpcodes.IDLE: 21>¶
-
-
class
ducky.cpu.instructions.
INB
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._IN
-
mnemonic
= 'inb'¶
-
opcode
= <DuckyOpcodes.INB: 45>¶
-
-
class
ducky.cpu.instructions.
INC
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor_R
-
mnemonic
= 'inc'¶
-
opcode
= <DuckyOpcodes.INC: 26>¶
-
-
class
ducky.cpu.instructions.
INS
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._IN
-
mnemonic
= 'ins'¶
-
opcode
= <DuckyOpcodes.INS: 44>¶
-
-
class
ducky.cpu.instructions.
INT
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor_RI
-
mnemonic
= 'int'¶
-
opcode
= <DuckyOpcodes.INT: 13>¶
-
-
class
ducky.cpu.instructions.
INW
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._IN
-
mnemonic
= 'inw'¶
-
opcode
= <DuckyOpcodes.INW: 43>¶
-
-
class
ducky.cpu.instructions.
IPI
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor_R_RI
-
mnemonic
= 'ipi'¶
-
opcode
= <DuckyOpcodes.IPI: 23>¶
-
-
class
ducky.cpu.instructions.
InstructionSet
[source]¶ Bases:
object
-
instruction_set_id
= None¶
-
instructions
= []¶
-
opcodes
= None¶
-
-
class
ducky.cpu.instructions.
J
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._JUMP
-
mnemonic
= 'j'¶
-
opcode
= <DuckyOpcodes.J: 46>¶
-
-
class
ducky.cpu.instructions.
LA
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._LOAD_IMM
-
mnemonic
= 'la'¶
-
opcode
= <DuckyOpcodes.LA: 8>¶
-
relative_address
= True¶
-
-
class
ducky.cpu.instructions.
LB
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._LOAD
-
mnemonic
= 'lb'¶
-
opcode
= <DuckyOpcodes.LB: 3>¶
-
-
class
ducky.cpu.instructions.
LI
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._LOAD_IMM
-
mnemonic
= 'li'¶
-
opcode
= <DuckyOpcodes.LI: 9>¶
-
-
class
ducky.cpu.instructions.
LIU
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._LOAD_IMM
-
mnemonic
= 'liu'¶
-
opcode
= <DuckyOpcodes.LIU: 10>¶
-
-
class
ducky.cpu.instructions.
LPM
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor
-
mnemonic
= 'lpm'¶
-
opcode
= <DuckyOpcodes.LPM: 22>¶
-
-
class
ducky.cpu.instructions.
LS
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._LOAD
-
mnemonic
= 'ls'¶
-
opcode
= <DuckyOpcodes.LS: 2>¶
-
-
class
ducky.cpu.instructions.
LW
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._LOAD
-
mnemonic
= 'lw'¶
-
opcode
= <DuckyOpcodes.LW: 1>¶
-
-
class
ducky.cpu.instructions.
MOD
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BINOP
-
mnemonic
= 'mod'¶
-
opcode
= <DuckyOpcodes.MOD: 33>¶
-
-
class
ducky.cpu.instructions.
MOV
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor_R_R
-
mnemonic
= 'mov'¶
-
opcode
= <DuckyOpcodes.MOV: 11>¶
-
-
class
ducky.cpu.instructions.
MUL
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BINOP
-
mnemonic
= 'mul'¶
-
opcode
= <DuckyOpcodes.MUL: 30>¶
-
-
class
ducky.cpu.instructions.
NOP
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor
-
mnemonic
= 'nop'¶
-
opcode
= <DuckyOpcodes.NOP: 0>¶
-
-
class
ducky.cpu.instructions.
NOT
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor_R
-
mnemonic
= 'not'¶
-
opcode
= <DuckyOpcodes.NOT: 37>¶
-
-
class
ducky.cpu.instructions.
OR
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BITOP
-
mnemonic
= 'or'¶
-
opcode
= <DuckyOpcodes.OR: 35>¶
-
-
class
ducky.cpu.instructions.
OUTB
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._OUT
-
mnemonic
= 'outb'¶
-
opcode
= <DuckyOpcodes.OUTB: 42>¶
-
-
class
ducky.cpu.instructions.
OUTS
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._OUT
-
mnemonic
= 'outs'¶
-
opcode
= <DuckyOpcodes.OUTS: 41>¶
-
-
class
ducky.cpu.instructions.
OUTW
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._OUT
-
mnemonic
= 'outw'¶
-
opcode
= <DuckyOpcodes.OUTW: 40>¶
-
-
class
ducky.cpu.instructions.
POP
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor_R
-
mnemonic
= 'pop'¶
-
opcode
= <DuckyOpcodes.POP: 25>¶
-
-
class
ducky.cpu.instructions.
PUSH
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor_RI
-
mnemonic
= 'push'¶
-
opcode
= <DuckyOpcodes.PUSH: 24>¶
-
-
class
ducky.cpu.instructions.
RET
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor
-
mnemonic
= 'ret'¶
-
opcode
= <DuckyOpcodes.RET: 16>¶
-
-
class
ducky.cpu.instructions.
RETINT
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor
-
mnemonic
= 'retint'¶
-
opcode
= <DuckyOpcodes.RETINT: 14>¶
-
-
class
ducky.cpu.instructions.
RST
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor
-
mnemonic
= 'rst'¶
-
opcode
= <DuckyOpcodes.RST: 19>¶
-
-
class
ducky.cpu.instructions.
SETE
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._SET
-
mnemonic
= 'sete'¶
-
-
class
ducky.cpu.instructions.
SETG
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._SET
-
mnemonic
= 'setg'¶
-
-
class
ducky.cpu.instructions.
SETGE
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._SET
-
mnemonic
= 'setge'¶
-
-
class
ducky.cpu.instructions.
SETL
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._SET
-
mnemonic
= 'setl'¶
-
-
class
ducky.cpu.instructions.
SETLE
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._SET
-
mnemonic
= 'setle'¶
-
-
class
ducky.cpu.instructions.
SETNE
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._SET
-
mnemonic
= 'setne'¶
-
-
class
ducky.cpu.instructions.
SETNO
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._SET
-
mnemonic
= 'setno'¶
-
-
class
ducky.cpu.instructions.
SETNS
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._SET
-
mnemonic
= 'setns'¶
-
-
class
ducky.cpu.instructions.
SETNZ
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._SET
-
mnemonic
= 'setnz'¶
-
-
class
ducky.cpu.instructions.
SETO
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._SET
-
mnemonic
= 'seto'¶
-
-
class
ducky.cpu.instructions.
SETS
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._SET
-
mnemonic
= 'sets'¶
-
-
class
ducky.cpu.instructions.
SETZ
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._SET
-
mnemonic
= 'setz'¶
-
-
class
ducky.cpu.instructions.
SHIFTL
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BITOP
-
mnemonic
= 'shiftl'¶
-
opcode
= <DuckyOpcodes.SHIFTL: 38>¶
-
-
class
ducky.cpu.instructions.
SHIFTR
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BITOP
-
mnemonic
= 'shiftr'¶
-
opcode
= <DuckyOpcodes.SHIFTR: 39>¶
-
-
class
ducky.cpu.instructions.
SIS
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor_RI
-
mnemonic
= 'sis'¶
-
opcode
= <DuckyOpcodes.SIS: 63>¶
-
-
class
ducky.cpu.instructions.
STB
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._STORE
-
mnemonic
= 'stb'¶
-
opcode
= <DuckyOpcodes.STB: 6>¶
-
-
class
ducky.cpu.instructions.
STI
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor
-
mnemonic
= 'sti'¶
-
opcode
= <DuckyOpcodes.STI: 18>¶
-
-
class
ducky.cpu.instructions.
STS
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._STORE
-
mnemonic
= 'sts'¶
-
opcode
= <DuckyOpcodes.STS: 5>¶
-
-
class
ducky.cpu.instructions.
STW
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._STORE
-
mnemonic
= 'stw'¶
-
opcode
= <DuckyOpcodes.STW: 4>¶
-
-
class
ducky.cpu.instructions.
SUB
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BINOP
-
mnemonic
= 'sub'¶
-
opcode
= <DuckyOpcodes.SUB: 29>¶
-
-
class
ducky.cpu.instructions.
SWP
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor_R_R
-
mnemonic
= 'swp'¶
-
opcode
= <DuckyOpcodes.SWP: 12>¶
-
-
class
ducky.cpu.instructions.
UDIV
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BINOP
-
mnemonic
= 'udiv'¶
-
opcode
= <DuckyOpcodes.UDIV: 32>¶
-
-
class
ducky.cpu.instructions.
XOR
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BITOP
-
mnemonic
= 'xor'¶
-
opcode
= <DuckyOpcodes.XOR: 36>¶
-
-
ducky.cpu.instructions.
update_arith_flags
(core, reg)[source]¶ Set relevant arithmetic flags according to content of registers. Flags are set to zero at the beginning, then content of each register is examined, and
S
andZ
flags are set.E
flag is not touched,O
flag is set to zero.Parameters: reg (u32_t) – register
ducky.cpu.registers module¶
-
class
ducky.cpu.registers.
Registers
[source]¶ Bases:
enum.IntEnum
-
CNT
= <Registers.CNT: 33>¶
-
FP
= <Registers.FP: 30>¶
-
IP
= <Registers.IP: 32>¶
-
R00
= <Registers.R00: 0>¶
-
R01
= <Registers.R01: 1>¶
-
R02
= <Registers.R02: 2>¶
-
R03
= <Registers.R03: 3>¶
-
R04
= <Registers.R04: 4>¶
-
R05
= <Registers.R05: 5>¶
-
R06
= <Registers.R06: 6>¶
-
R07
= <Registers.R07: 7>¶
-
R08
= <Registers.R08: 8>¶
-
R09
= <Registers.R09: 9>¶
-
R10
= <Registers.R10: 10>¶
-
R11
= <Registers.R11: 11>¶
-
R12
= <Registers.R12: 12>¶
-
R13
= <Registers.R13: 13>¶
-
R14
= <Registers.R14: 14>¶
-
R15
= <Registers.R15: 15>¶
-
R16
= <Registers.R16: 16>¶
-
R17
= <Registers.R17: 17>¶
-
R18
= <Registers.R18: 18>¶
-
R19
= <Registers.R19: 19>¶
-
R20
= <Registers.R20: 20>¶
-
R21
= <Registers.R21: 21>¶
-
R22
= <Registers.R22: 22>¶
-
R23
= <Registers.R23: 23>¶
-
R24
= <Registers.R24: 24>¶
-
R25
= <Registers.R25: 25>¶
-
R26
= <Registers.R26: 26>¶
-
R27
= <Registers.R27: 27>¶
-
R28
= <Registers.R28: 28>¶
-
R29
= <Registers.R29: 29>¶
-
REGISTER_COUNT
= <Registers.REGISTER_COUNT: 34>¶
-
REGISTER_SPECIAL
= <Registers.FP: 30>¶
-
SP
= <Registers.SP: 31>¶
-
Module contents¶
-
class
ducky.cpu.
CPU
(machine, cpuid, memory_controller, cores=1)[source]¶ Bases:
ducky.interfaces.ISnapshotable
,ducky.interfaces.IMachineWorker
-
class
ducky.cpu.
CPUCore
(coreid, cpu, memory_controller)[source]¶ Bases:
ducky.interfaces.ISnapshotable
,ducky.interfaces.IMachineWorker
This class represents the main workhorse, one of CPU cores. Reads instructions, executes them, has registers, caches, handles interrupts, ...
Parameters: - coreid (int) – id of this core. Usually, it’s its serial number but it has no special meaning.
- cpu (ducky.cpu.CPU) – CPU that owns this core.
- memory_controller (ducky.mm.MemoryController) – use this controller to access main memory.
-
check_protected_ins
()[source]¶ Raise
AccessViolationError
if core is not running in privileged mode.This method should be used by instruction handlers that require privileged mode, e.g. protected instructions.
Raises: AccessViolationError – if the core is not in privileged mode
-
create_frame
()[source]¶ Create new call stack frame. Push
IP
andFP
registers and setFP
value toSP
.
-
destroy_frame
()[source]¶ Destroy current call frame. Pop
FP
andIP
from stack, by poppingFP
restores previous frame.Raises: CPUException – if current frame does not match last created frame.
-
do_int
(index)[source]¶ Handle software interrupt. Real software interrupts cause CPU state to be saved and new stack and register values are prepared by
__enter_interrupt
method, virtual interrupts are simply triggered without any prior changes of CPU state.Parameters: index (int) – interrupt number
-
exit_interrupt
()[source]¶ Restore CPU state after running a interrupt routine. Call frame is destroyed, registers are restored, stack is returned back to memory pool.
-
flags
¶
-
raw_pop
()[source]¶ Pop value from stack. 4 byte number is read from address in
SP
, thenSP
is incremented by four.Returns: popped value Return type: u32
-
raw_push
(val)[source]¶ Push value on stack.
SP
is decremented by four, and value is written at this new address.Parameters: val (u32) – value to be pushed
-
reset
(new_ip=0)[source]¶ Reset core’s state. All registers are set to zero, all flags are set to zero, except
HWINT
flag which is set to one, andIP
is set to requested value.Parameters: new_ip (u32_t) – new IP
value, defaults to zero
-
class
ducky.cpu.
CPUCoreState
[source]¶ Bases:
ducky.snapshot.SnapshotNode
-
exception
ducky.cpu.
CPUException
(msg, core=None, ip=None)[source]¶ Bases:
exceptions.Exception
Base class for CPU-related exceptions.
Parameters: - msg (string) – message describing exceptional state.
- core (ducky.cpu.CPUCore) – CPU core that raised exception, if any.
- ip (u32_t) – address of an instruction that caused exception, if any.
-
class
ducky.cpu.
CPUState
(*fields)[source]¶ Bases:
ducky.snapshot.SnapshotNode
-
class
ducky.cpu.
CoreFlags
[source]¶ Bases:
ducky.util.Flags
-
ducky.cpu.
DEFAULT_CORE_INST_CACHE_SIZE
= 256¶ Default size of core instruction cache, in instructions.
-
ducky.cpu.
DEFAULT_IVT_ADDRESS
= 0¶ Default IVT address
-
ducky.cpu.
DEFAULT_PT_ADDRESS
= 65536¶ Default PT address
-
class
ducky.cpu.
InstructionCache
(mmu, size, *args, **kwargs)[source]¶ Bases:
ducky.util.LRUCache
Simple instruction cache class, based on LRU dictionary, with a limited size.
Parameters: - core (ducky.cpu.CPUCore) – CPU core that owns this cache.
- size (int) – maximal number of entries this cache can store.
-
class
ducky.cpu.
InterruptVector
(ip=0, sp=0)[source]¶ Bases:
object
Interrupt vector table entry.
-
SIZE
= 8¶
-
-
exception
ducky.cpu.
InvalidInstructionSetError
(inst_set, *args, **kwargs)[source]¶ Bases:
ducky.cpu.CPUException
Raised when switch to unknown or invalid instruction set is requested.
Parameters: inst_set (int) – instruction set id.
-
exception
ducky.cpu.
InvalidOpcodeError
(opcode, *args, **kwargs)[source]¶ Bases:
ducky.cpu.CPUException
Raised when unknown or invalid opcode is found in instruction.
Parameters: opcode (int) – wrong opcode.
-
class
ducky.cpu.
MMU
(core, memory_controller)[source]¶ Bases:
ducky.interfaces.ISnapshotable
Memory management unit (aka MMU) provides a single point handling all core’s memory operations. All memory reads and writes must go through this unit, which is then responsible for all translations, access control, and caching.
Parameters: - core (ducky.cpu.CPUCore) – parent core.
- memory_controller (ducky.mm.MemoryController) – memory controller that provides access to the main memory.
-
check_access
(access, addr, align=None)[source]¶ Check attempted access against PTE. Be aware that each check can be turned off by configuration file.
Parameters: - access –
read
,write
orexecute
. - addr (u24) – memory address.
- align (int) – if set, operation is expected to be aligned to this boundary.
Raises: ducky.errors.AccessViolationError – when access is denied.
- access –
-
ducky.cpu.
cmd_set_core
(console, cmd)[source]¶ Set core address of default core used by control commands: sc <coreid>
-
ducky.cpu.
do_log_cpu_core_state
(core, logger=None, disassemble=True, inst_set=None)[source]¶ Log state of a CPU core. Content of its registers, and other interesting or useful internal variables are logged.
Parameters: - core (ducky.cpu.CPUCore) – core whose state should be logged.
- logger – called for each line of output to actualy log it. By default,
core’s
ducky.cpu.CPUCore.DEBUG()
method is used.
-
ducky.cpu.
log_cpu_core_state
(*args, **kwargs)[source]¶ This is a wrapper for ducky.cpu.do_log_cpu_core_state function. Its main purpose is to be removed when debug mode is not set, therefore all debug calls of ducky.cpu.do_log_cpu_core_state will disappear from code, making such code effectively “quiet”.
ducky.debugging module¶
Virtual machine debugging tools - break points, watch points, etc.
Create “point” that’s triggered when a condition is satisfied (e.g. processor executes instruction on specified address, memory at specified address was modified, etc. Then, create “action” (e.g. suspend core), and bind both pieces together - when point gets triggered, execute list of actions.
-
class
ducky.debugging.
Action
(logger)[source]¶ Bases:
object
Base class of all debugging actions.
Parameters: logger (logging.Logger) – logger instance used for logging. -
act
(core, point)[source]¶ This method is called when “action” is executed. Implement it in child classes to give child actions a functionality.
Parameters: - core (ducky.cpu.CPUCore) – CPU core where point was triggered.
- point (ducky.debugging.Point) – point that was triggered.
-
-
class
ducky.debugging.
BreakPoint
(debugging_set, ip, *args, **kwargs)[source]¶ Bases:
ducky.debugging.Point
-
class
ducky.debugging.
LogMemoryContentAction
(logger, address, size)[source]¶ Bases:
ducky.debugging.LogValueAction
When triggered, logs content of a specified location in memory.
Parameters: - logger (logging.Logger) – logger instance used for logging.
- address (u32_t) – memory location.
- size (int) – size of logged number, in bytes.
-
class
ducky.debugging.
LogRegisterContentAction
(logger, registers)[source]¶ Bases:
ducky.debugging.LogValueAction
When triggered, logs content of a specified register.
Parameters: - logger (logging.Logger) – logger instance used for logging.
- registers (list) – list of register names.
-
class
ducky.debugging.
LogValueAction
(logger, size)[source]¶ Bases:
ducky.debugging.Action
This is the base class for actions that log a numerical values.
Parameters: - logger (logging.Logger) – logger instance used for logging.
- size (int) – size of logged number, in bytes.
-
get_message
(core, point)[source]¶ Return message that, formatted with output of
get_values()
, will be shown to user.Parameters: - core (ducky.cpu.CPUCore) – core point was triggered on.
- point (ducky.debugging.Point) – triggered point.
Return type: string
Returns: information message.
-
get_values
(core, point)[source]¶ Prepare dictionary with values for message that will be shown to the user.
Parameters: - core (ducky.cpu.CPUCore) – core point was triggered on.
- point (ducky.debugging.Point) – triggered point.
Return type: dict
Returns: dictionary that will be passed to message
format()
method.
-
class
ducky.debugging.
MemoryWatchPoint
(debugging_set, address, read, *args, **kwargs)[source]¶ Bases:
ducky.debugging.Point
-
class
ducky.debugging.
Point
(debugging_set, active=True, countdown=0)[source]¶ Bases:
object
Base class of all debugging points.
Parameters: - debugging_set (ducky.debugging.DebuggingSet) – debugging set this point belongs to.
- active (bool) – if not
True
, point is not active and will not trigger. - countdown (int) – if greater than zero, point has to trigger
countdown
times before its actions are executed for the first time.
-
is_triggered
(core, *args, **kwargs)[source]¶ Test point’s condition.
Parameters: core (ducky.cpu.CPUCore) – core requesting the test. Return type: bool Returns: True
if condition is satisfied.
-
class
ducky.debugging.
SuspendCoreAction
(logger)[source]¶ Bases:
ducky.debugging.Action
If executed, this action will suspend the CPU core that triggered its parent point.
-
class
ducky.debugging.
VMDebugOperationList
[source]¶ Bases:
enum.Enum
-
LOGGER_VERBOSITY
= <VMDebugOperationList.LOGGER_VERBOSITY: 0>¶
-
-
class
ducky.debugging.
VMVerbosityLevels
[source]¶ Bases:
enum.Enum
-
DEBUG
= <VMVerbosityLevels.DEBUG: 0>¶
-
ERROR
= <VMVerbosityLevels.ERROR: 3>¶
-
INFO
= <VMVerbosityLevels.INFO: 1>¶
-
WARNING
= <VMVerbosityLevels.WARNING: 2>¶
-
-
ducky.debugging.
cmd_bp_active
(console, cmd)[source]¶ Toggle “active” flag for a breakpoint: bp-active <id>
-
ducky.debugging.
cmd_bp_add_breakpoint
(console, cmd)[source]¶ Create new breakpoint: bp-break <#cpuid:#coreid> <address> [active] [countdown]
ducky.devices package¶
Submodules¶
ducky.devices.keyboard module¶
Keyboard controller - provides events for pressed and released keys.
-
class
ducky.devices.keyboard.
Backend
(machine, name, port=None, irq=None)[source]¶ Bases:
ducky.devices.IRQProvider
,ducky.devices.IOProvider
,ducky.devices.DeviceBackend
ducky.devices.rtc module¶
-
class
ducky.devices.rtc.
RTC
(machine, name, frequency=None, port=None, irq=None, *args, **kwargs)[source]¶ Bases:
ducky.devices.IRQProvider
,ducky.devices.IOProvider
,ducky.devices.Device
ducky.devices.snapshot module¶
-
class
ducky.devices.snapshot.
DefaultFileSnapshotStorage
(machine, name, filepath=None, *args, **kwargs)[source]¶
ducky.devices.storage module¶
Persistent storage support.
Several different persistent storages can be attached to a virtual machine, each with its own id. This module provides methods for manipulating their content. By default, storages operate with blocks of constant, standard size, though this is not a mandatory requirement - storage with different block size, or even with variable block size can be implemented.
Each block has its own id. Block IO operations read or write one or more blocks to or from a device. IO is requested by invoking the virtual interrupt, with properly set values in registers.
-
ducky.devices.storage.
BLOCK_SIZE
= 1024¶ Size of block, in bytes.
-
class
ducky.devices.storage.
BlockIO
(machine, name, port=None, irq=None, *args, **kwargs)[source]¶ Bases:
ducky.devices.IRQProvider
,ducky.devices.IOProvider
,ducky.devices.Device
-
class
ducky.devices.storage.
FileBackedStorage
(machine, name, filepath=None, *args, **kwargs)[source]¶ Bases:
ducky.devices.storage.Storage
Storage that saves its content into a regular file.
-
class
ducky.devices.storage.
Storage
(machine, name, sid=None, size=None, *args, **kwargs)[source]¶ Bases:
ducky.devices.Device
Base class for all block storages.
Parameters: - machine (ducky.machine.Machine) – machine storage is attached to.
- sid (int) – id of storage.
- size (int) – size of storage, in bytes.
-
do_read_blocks
(start, cnt)[source]¶ Read one or more blocks from device to internal buffer.
Child classes are supposed to reimplement this particular method.
Parameters: - start (u32_t) – index of the first requested block.
- cnt (u32_t) – number of blocks to read.
-
do_write_blocks
(start, cnt, buff)[source]¶ Write one or more blocks from internal buffer to device.
Child classes are supposed to reimplement this particular method.
Parameters: - start (u32_t) – index of the first requested block.
- cnt (u32_t) – number of blocks to write.
-
read_blocks
(start, cnt)[source]¶ Read one or more blocks from device to internal buffer.
Child classes should not reimplement this method, as it provides checks common for (probably) all child classes.
Parameters: - start (u32_t) – index of the first requested block.
- cnt (u32_t) – number of blocks to read.
-
write_blocks
(start, cnt, buff)[source]¶ Write one or more blocks from internal buffer to device.
Child classes should not reimplement this method, as it provides checks common for (probably) all child classes.
Parameters: - start (u32_t) – index of the first requested block.
- cnt (u32_t) – number of blocks to write.
ducky.devices.terminal module¶
Terminal is a device that groups together character two input and output devices, thus forming a simple channel for bidirectional communication between VM and user.
- Terminal has two slave frontends:
- input, usually a keyboard
- output, from simple TTY to more powerful devices
Terminal then manages input and input streams, passing them to its slave devices, which then transports events between streams and VM’s comm channel.
-
class
ducky.devices.terminal.
StandardIOTerminal
(machine, name, input_device=None, output_device=None, *args, **kwargs)[source]¶
-
class
ducky.devices.terminal.
StreamIOTerminal
(machine, name, input_device=None, output_device=None, *args, **kwargs)[source]¶
-
class
ducky.devices.terminal.
Terminal
(machine, name, echo=False, *args, **kwargs)[source]¶ Bases:
ducky.devices.DeviceFrontend
ducky.devices.tty module¶
Very simple character device that just “prints” characters on the screen.
It does not care about dimensions of the display, it kknow only how to
“print” characters. Suited for the most basic output possible - just “print”
chars by writing to this device, and you’ll get this written into a stream
attached to the frontend (stdout
, file, ...).
-
class
ducky.devices.tty.
Backend
(machine, name, stream=None, port=None, *args, **kwargs)[source]¶ Bases:
ducky.devices.IOProvider
,ducky.devices.DeviceBackend
-
class
ducky.devices.tty.
Frontend
(machine, name)[source]¶ Bases:
ducky.devices.DeviceFrontend
ducky.devices.svga module¶
SimpleVGA is very basic implementation of VGA-like device, with text and graphic modes.
-
class
ducky.devices.svga.
Char
[source]¶ Bases:
_ctypes.Structure
-
bg
¶ Structure/Union member
-
blink
¶ Structure/Union member
-
codepoint
¶ Structure/Union member
-
fg
¶ Structure/Union member
-
unused
¶ Structure/Union member
-
-
ducky.devices.svga.
DEFAULT_BOOT_MODE
= (t, 80, 25, 1)¶ Default boot mode
-
ducky.devices.svga.
DEFAULT_MEMORY_BANKS
= 8¶ Default number of memory banks
-
ducky.devices.svga.
DEFAULT_MEMORY_SIZE
= 65536¶ Default memory size, in bytes
-
ducky.devices.svga.
DEFAULT_MODES
= [(g, 320, 200, 1), (t, 80, 25, 2), (t, 80, 25, 1)]¶ Default list of available modes
-
ducky.devices.svga.
DEFAULT_PORT_RANGE
= 1008¶ Default address of command port
-
class
ducky.devices.svga.
Display
(machine, name, gpu=None, stream_out=None, *args, **kwargs)[source]¶ Bases:
ducky.devices.Device
-
class
ducky.devices.svga.
Mode
(_type, width, height, depth)[source]¶ Bases:
object
-
class
ducky.devices.svga.
SimpleVGA
(machine, name, port=None, memory_size=None, memory_address=None, memory_banks=None, modes=None, boot_mode=None, *args, **kwargs)[source]¶ Bases:
ducky.devices.IOProvider
,ducky.devices.Device
SimpleVGA is very basic implementation of VGA-like device, with text and graphic modes.
It has its own graphic memory (“buffer”), split into several banks of the same size. Always only one bank can be directly accessed, by having it mapped into CPU’s address space.
Parameters: - machine (ducky.machine.Machine) – machine this device belongs to.
- name (string) – name of this device.
- port (u16) – address of the command port.
- memory_size (int) – size of graphic memory.
- memory_address (u24) – address of graphic memory - to this address is graphic buffer mapped. Must be specified, there is no default value.
- memory_banks (int) – number of memory banks.
- modes (list) – list of
ducky.devices.svga.Mode
objects, list of supported modes. - boot_mode (tuple) – this mode will be set when device boots up.
-
class
ducky.devices.svga.
SimpleVGACommands
[source]¶ Bases:
enum.IntEnum
-
COLS
= <SimpleVGACommands.COLS: 33>¶
-
DEPTH
= <SimpleVGACommands.DEPTH: 35>¶
-
GRAPHIC
= <SimpleVGACommands.GRAPHIC: 32>¶
-
MEMORY_BANK_ID
= <SimpleVGACommands.MEMORY_BANK_ID: 48>¶
-
REFRESH
= <SimpleVGACommands.REFRESH: 2>¶
-
RESET
= <SimpleVGACommands.RESET: 32769>¶
-
ROWS
= <SimpleVGACommands.ROWS: 34>¶
-
-
class
ducky.devices.svga.
SimpleVGAMemoryPage
(dev, *args, **kwargs)[source]¶ Bases:
ducky.mm.ExternalMemoryPage
Memory page handling MMIO of sVGA device.
Parameters: dev (ducky.devices.svga.SimpleVGA) – sVGA device this page belongs to.
Module contents¶
-
class
ducky.devices.
DeviceBackend
(machine, klass, name)[source]¶ Bases:
ducky.devices.Device
-
class
ducky.devices.
DeviceFrontend
(machine, klass, name)[source]¶ Bases:
ducky.devices.Device
ducky.errors module¶
-
exception
ducky.errors.
AccessViolationError
(message=None)[source]¶ Bases:
ducky.errors.Error
-
exception
ducky.errors.
AssemblerError
(location=None, message=None, line=None, info=None)[source]¶ Bases:
ducky.errors.Error
-
exception
ducky.errors.
DisassembleMismatchError
(**kwargs)[source]¶ Bases:
ducky.errors.AssemblerError
-
exception
ducky.errors.
EncodingLargeValueError
(**kwargs)[source]¶ Bases:
ducky.errors.AssemblerError
-
exception
ducky.errors.
IncompatibleLinkerFlagsError
(message=None)[source]¶ Bases:
ducky.errors.Error
-
exception
ducky.errors.
IncompleteDirectiveError
(**kwargs)[source]¶ Bases:
ducky.errors.AssemblerError
-
exception
ducky.errors.
InvalidResourceError
(message=None)[source]¶ Bases:
ducky.errors.Error
-
exception
ducky.errors.
TooManyLabelsError
(**kwargs)[source]¶ Bases:
ducky.errors.AssemblerError
-
exception
ducky.errors.
UnalignedJumpTargetError
(**kwargs)[source]¶ Bases:
ducky.errors.AssemblerError
-
exception
ducky.errors.
UnknownFileError
(**kwargs)[source]¶ Bases:
ducky.errors.AssemblerError
-
exception
ducky.errors.
UnknownPatternError
(**kwargs)[source]¶ Bases:
ducky.errors.AssemblerError
-
exception
ducky.errors.
UnknownSymbolError
(message=None)[source]¶ Bases:
ducky.errors.Error
ducky.hdt module¶
Hardware Description Table structures.
-
class
ducky.hdt.
HDT
(logger, config=None)[source]¶ Bases:
object
Root of HDT. Provides methods for creating HDT for a given machine configuration.
Parameters: - logger (logging.Logger) – logger instance used for logging.
- config (ducky.config.MachineConfig) – configuration file HDT should reflect.
-
klasses
= [<class 'ducky.hdt.HDTEntry_Memory'>, <class 'ducky.hdt.HDTEntry_CPU'>, <class 'ducky.hdt.HDTEntry_Argument'>]¶
-
class
ducky.hdt.
HDTEntry
(entry_type, length)[source]¶ Bases:
ducky.hdt.HDTStructure
Base class of all HDT entries.
Each entry has at least two fields, type and length. Other fields depend on type of entry, and follow immediately after length field.
Parameters: - type (u16_t) – type of entry. See
ducky.hdt.HDTEntryTypes
. - length (u16_t) – length of entry, in bytes.
- type (u16_t) – type of entry. See
-
class
ducky.hdt.
HDTEntryTypes
[source]¶ Bases:
enum.IntEnum
Types of different HDT entries.
-
ARGUMENT
= <HDTEntryTypes.ARGUMENT: 3>¶
-
CPU
= <HDTEntryTypes.CPU: 1>¶
-
MEMORY
= <HDTEntryTypes.MEMORY: 2>¶
-
UNDEFINED
= <HDTEntryTypes.UNDEFINED: 0>¶
-
-
class
ducky.hdt.
HDTEntry_Argument
(arg_name, arg_type, arg_value)[source]¶ Bases:
ducky.hdt.HDTEntry
-
MAX_NAME_LENGTH
= 13¶
-
length
¶ Structure/Union member
-
name
¶ Structure/Union member
-
name_length
¶ Structure/Union member
-
type
¶ Structure/Union member
-
value
¶ Structure/Union member
-
value_length
¶ Structure/Union member
-
-
class
ducky.hdt.
HDTEntry_CPU
(logger, config)[source]¶ Bases:
ducky.hdt.HDTEntry
HDT entry describing CPU configuration.
Parameters: - nr_cpus (u16_t) – number of CPUs.
- nr_cores (u16_t) – number of cores per CPU.
-
length
¶ Structure/Union member
-
nr_cores
¶ Structure/Union member
-
nr_cpus
¶ Structure/Union member
-
type
¶ Structure/Union member
-
class
ducky.hdt.
HDTEntry_Memory
(logger, config)[source]¶ Bases:
ducky.hdt.HDTEntry
HDT entry describing memory configuration.
Parameters: size (u32_t) – size of memory, in bytes. -
length
¶ Structure/Union member
-
size
¶ Structure/Union member
-
type
¶ Structure/Union member
-
-
class
ducky.hdt.
HDTHeader
[source]¶ Bases:
ducky.hdt.HDTStructure
HDT header. Contains magic number, number of HDT entries that immediately follow header.
-
entries
¶ Structure/Union member
-
length
¶ Structure/Union member
-
magic
¶ Structure/Union member
-
-
ducky.hdt.
HDT_MAGIC
= 1298034544¶ Magic number present in HDT header
ducky.interfaces module¶
-
class
ducky.interfaces.
IMachineWorker
[source]¶ Bases:
object
Base class for objects that provide pluggable service to others.
-
boot
(*args)[source]¶ Prepare for providing the service. After this call, it may be requested by others.
-
die
(exc)[source]¶ Exceptional state requires immediate termination of service. Probably no object will ever have need to call others’
die
method, it’s intended for internal use only.
-
halt
()[source]¶ Terminate service. It will never be requested again, object can destroy its internal state, and free allocated resources.
-
-
class
ducky.interfaces.
ISnapshotable
[source]¶ Bases:
object
Base class for objects that can be saved into a snapshot.
-
load_state
(state)[source]¶ Restore state of the object.
Parameters: state (ducky.snapshot.SnapshotNode) – snapshot node containing saved state.
-
save_state
(parent)[source]¶ Create state of the object, and attach it to a parent snapshot node.
Parameters: parent (ducky.interfaces.ISnapshotable) – parent snapshot node.
-
ducky.log module¶
ducky.machine module¶
ducky.machine.Machine
is the virtual machine. Each instance
represents self-contained virtual machine, with all its devices, memory, CPUs
and other necessary properties.
-
class
ducky.machine.
IRQRouterTask
(machine)[source]¶ Bases:
ducky.interfaces.IReactorTask
This task is responsible for distributing triggered IRQs between CPU cores. When IRQ is triggered, IRQ source (i.e. device that requires attention) is appended to this tasks queue (
ducky.machine.IRQRouterTask.qeueu
). As long as this queue is not empty, this task pops IRQ sources, selects free CPU core, and by calling itsducky.cpu.CPUCore.irq()
method core takes reponsibility for executing interrupt routine.Parameters: machine (ducky.machine.Machine) – machine this task belongs to.
-
class
ducky.machine.
Machine
(logger=None, stdin=None, stdout=None, stderr=None)[source]¶ Bases:
ducky.interfaces.ISnapshotable
,ducky.interfaces.IMachineWorker
Virtual machine itself.
-
capture_state
(suspend=False)[source]¶ Capture current state of the VM, and store it in it’s last_state attribute.
Parameters: suspend (bool) – if True, suspend VM before taking snapshot.
-
core
(cid)[source]¶ Find CPU core by its string id.
Parameters: cid (string) – id of searched CPU core, in the form #<cpuid>:#<coreid>. Return type: ducky.cpu.CPUCore
Returns: found core Raises: ducky.errors.InvalidResourceError – when no such core exists.
-
cores
¶ Get list of all cores in the machine.
Return type: list Returns: list of ducky.cpu.CPUCore
instances
-
exit_code
¶
-
get_device_by_name
(name, klass=None)[source]¶ Get device by its name and class.
Parameters: - name (string) – name of the device.
- klass (string) – if set, search only devices with this class.
Return type: Returns: found device
Raises: ducky.errors.InvalidResourceError – when no such device exists
-
get_storage_by_id
(sid)[source]¶ Get storage by its id.
Parameters: sid (int) – id of storage caller is looking for. Return type: ducky.devices.Device
Returns: found device. Raises: ducky.errors.InvalidResourceError – when no such storage exists.
-
-
class
ducky.machine.
MachineState
[source]¶ Bases:
ducky.snapshot.SnapshotNode
ducky.mm package¶
Submodules¶
ducky.mm.binary module¶
-
class
ducky.mm.binary.
File
(logger, stream)[source]¶ Bases:
ducky.util.BinaryFile
-
MAGIC
= 57005¶
-
VERSION
= 1¶
-
-
class
ducky.mm.binary.
FileFlags
[source]¶ Bases:
ducky.util.Flags
-
field
= ('mmapable', <class 'ctypes.c_ushort'>, 1)¶
-
-
class
ducky.mm.binary.
FileFlagsEncoding
[source]¶ Bases:
_ctypes.Structure
-
mmapable
¶ Structure/Union member
-
-
class
ducky.mm.binary.
FileHeader
[source]¶ Bases:
_ctypes.Structure
-
flags
¶ Structure/Union member
-
magic
¶ Structure/Union member
-
sections
¶ Structure/Union member
-
version
¶ Structure/Union member
-
-
class
ducky.mm.binary.
RelocEntry
[source]¶ Bases:
_ctypes.Structure
-
flags
¶ Structure/Union member
-
name
¶ Structure/Union member
-
patch_add
¶ Structure/Union member
-
patch_address
¶ Structure/Union member
-
patch_offset
¶ Structure/Union member
-
patch_section
¶ Structure/Union member
-
patch_size
¶ Structure/Union member
-
-
class
ducky.mm.binary.
RelocFlags
[source]¶ Bases:
ducky.util.Flags
-
field
= ('inst_aligned', <class 'ctypes.c_ushort'>, 1)¶
-
-
class
ducky.mm.binary.
RelocFlagsEncoding
[source]¶ Bases:
_ctypes.Structure
-
inst_aligned
¶ Structure/Union member
-
relative
¶ Structure/Union member
-
-
class
ducky.mm.binary.
SectionFlags
[source]¶ Bases:
ducky.util.Flags
-
field
= ('globally_visible', <class 'ctypes.c_ubyte'>, 1)¶
-
-
class
ducky.mm.binary.
SectionFlagsEncoding
[source]¶ Bases:
_ctypes.Structure
-
bss
¶ Structure/Union member
-
executable
¶ Structure/Union member
-
globally_visible
¶ Structure/Union member
-
loadable
¶ Structure/Union member
-
mmapable
¶ Structure/Union member
-
readable
¶ Structure/Union member
-
writable
¶ Structure/Union member
-
-
class
ducky.mm.binary.
SectionHeader
[source]¶ Bases:
_ctypes.Structure
-
base
¶ Structure/Union member
-
data_size
¶ Structure/Union member
-
file_size
¶ Structure/Union member
-
flags
¶ Structure/Union member
-
index
¶ Structure/Union member
-
items
¶ Structure/Union member
-
name
¶ Structure/Union member
-
offset
¶ Structure/Union member
-
padding
¶ Structure/Union member
-
type
¶ Structure/Union member
-
-
class
ducky.mm.binary.
SectionTypes
[source]¶ Bases:
enum.IntEnum
-
DATA
= <SectionTypes.DATA: 2>¶
-
RELOC
= <SectionTypes.RELOC: 5>¶
-
STRINGS
= <SectionTypes.STRINGS: 4>¶
-
SYMBOLS
= <SectionTypes.SYMBOLS: 3>¶
-
TEXT
= <SectionTypes.TEXT: 1>¶
-
UNKNOWN
= <SectionTypes.UNKNOWN: 0>¶
-
-
class
ducky.mm.binary.
SymbolDataTypes
[source]¶ Bases:
enum.IntEnum
-
ASCII
= <SymbolDataTypes.ASCII: 5>¶
-
BYTE
= <SymbolDataTypes.BYTE: 3>¶
-
CHAR
= <SymbolDataTypes.CHAR: 2>¶
-
FUNCTION
= <SymbolDataTypes.FUNCTION: 6>¶
-
INT
= <SymbolDataTypes.INT: 0>¶
-
SHORT
= <SymbolDataTypes.SHORT: 1>¶
-
STRING
= <SymbolDataTypes.STRING: 4>¶
-
UNKNOWN
= <SymbolDataTypes.UNKNOWN: 7>¶
-
-
class
ducky.mm.binary.
SymbolEntry
[source]¶ Bases:
_ctypes.Structure
-
address
¶ Structure/Union member
-
filename
¶ Structure/Union member
-
flags
¶ Structure/Union member
-
lineno
¶ Structure/Union member
-
name
¶ Structure/Union member
-
section
¶ Structure/Union member
-
size
¶ Structure/Union member
-
type
¶ Structure/Union member
-
-
class
ducky.mm.binary.
SymbolFlags
[source]¶ Bases:
ducky.util.Flags
-
field
= ('globally_visible', <class 'ctypes.c_ushort'>, 1)¶
-
Module contents¶
-
class
ducky.mm.
AnonymousMemoryPage
(controller, index)[source]¶ Bases:
ducky.mm.MemoryPage
“Anonymous” memory page - this page is just a plain array of bytes, and is not backed by any storage. Its content lives only in the memory.
Page is created with all bytes set to zero.
-
class
ducky.mm.
ExternalMemoryPage
(controller, index, data, offset=0)[source]¶ Bases:
ducky.mm.MemoryPage
Memory page backed by an external source. Source is an array of bytes, and can be provided by device driver, mmaped file, or by any other mean.
-
get
(offset)[source]¶ Get one byte from page. Override this method in case you need a different offset of requested byte.
Parameters: offset (int) – offset of the requested byte. Return type: int Returns: byte at position in page.
-
-
class
ducky.mm.
MMOperationList
[source]¶ Bases:
enum.IntEnum
-
ALLOC
= <MMOperationList.ALLOC: 3>¶
-
FREE
= <MMOperationList.FREE: 4>¶
-
MMAP
= <MMOperationList.MMAP: 6>¶
-
UNMMAP
= <MMOperationList.UNMMAP: 7>¶
-
UNUSED
= <MMOperationList.UNUSED: 5>¶
-
-
class
ducky.mm.
MemoryController
(machine, size=16777216)[source]¶ Bases:
object
Memory controller handles all operations regarding main memory.
Parameters: - machine (ducky.machine.Machine) – virtual machine that owns this controller.
- size (int) – size of memory, in bytes.
Raises: ducky.errors.InvalidResourceError – when memory size is not multiple of
ducky.mm.PAGE_SIZE
.-
alloc_page
(base=None)[source]¶ Allocate new anonymous page for usage. The first available index is used.
Parameters: base (int) – if set, start searching pages from this address. Returns: newly reserved page. Return type: ducky.mm.AnonymousMemoryPage
Raises: ducky.errors.InvalidResourceError – when there is no available page.
-
alloc_pages
(base=None, count=1)[source]¶ Allocate continuous sequence of anonymous pages.
Parameters: - base (u24) – if set, start searching pages from this address.
- count (int) – number of requested pages.
Returns: list of newly allocated pages.
Return type: list
ofducky.mm.AnonymousMemoryPage
Raises: ducky.errors.InvalidResourceError – when there is no available sequence of pages.
-
alloc_specific_page
(index)[source]¶ Allocate new anonymous page with specific index for usage.
Parameters: index (int) – allocate page with this particular index. Returns: newly reserved page. Return type: ducky.mm.AnonymousMemoryPage
Raises: ducky.errors.AccessViolationError – when page is already allocated.
-
free_page
(page)[source]¶ Free memory page when it’s no longer needed.
Parameters: page (ducky.mm.MemoryPage) – page to be freed.
-
free_pages
(page, count=1)[source]¶ Free a continuous sequence of pages when they are no longer needed.
Parameters: - page (ducky.mm.MemoryPage) – first page in series.
- count (int) – number of pages.
-
get_page
(index)[source]¶ Return memory page, specified by its index from the beginning of memory.
Parameters: index (int) – index of requested page. Return type: ducky.mm.MemoryPage
Raises: ducky.errors.AccessViolationError – when requested page is not allocated.
-
get_pages
(pages_start=0, pages_cnt=None, ignore_missing=False)[source]¶ Return list of memory pages.
Parameters: - pages_start (int) – index of the first page, 0 by default.
- pages_cnt (int) – number of pages to get, number of all memory pages by default.
- ignore_missing (bool) – if
True
, ignore missing pages,False
by default.
Raises: ducky.errors.AccessViolationError – when
ignore_missing == False
and there’s a missing page in requested range, this exception is rised.Returns: list of pages in area
Return type: list of
ducky.mm.MemoryPage
-
pages_in_area
(address=0, size=None, ignore_missing=False)[source]¶ Return list of memory pages.
Parameters: - address (u24) – beggining address of the area, by default 0.
- size (u24) – size of the area, by default the whole memory size.
- ignore_missing (bool) – if
True
, ignore missing pages,False
by default.
Raises: ducky.errors.AccessViolationError – when
ignore_missing == False
and there’s a missing page in requested range, this exception is rised.Returns: list of pages in area
Return type: list of
ducky.mm.MemoryPage
-
register_page
(pg)[source]¶ Install page object for a specific memory page. This method is intended for external objects, e.g. device drivers to install their memory page objects to handle memory-mapped IO.
Parameters: pg (ducky.mm.MemoryPage) – page to be installed Returns: installed page Return type: ducky.mm.AnonymousMemoryPage
Raises: ducky.errors.AccessViolationError – when there is already allocated page
-
unregister_page
(pg)[source]¶ Remove page object for a specific memory page. This method is intende for external objects, e.g. device drivers to remove their memory page objects handling memory-mapped IO.
Parameters: pg (ducky.mm.MemoryPage) – page to be removed Raises: ducky.errors.AccessViolationError – when there is no allocated page
-
class
ducky.mm.
MemoryPage
(controller, index)[source]¶ Bases:
object
Base class for all memory pages of any kinds.
Memory page has a set of boolean flags that determine access to and behavior of the page.
Flag Meaning Default read
page is readable by executed instructions False
write
page is writable by executed instructions False
execute
content of the page can be used as executable instructions False
dirty
there have been write access to this page, its content has changed False
Parameters: - controller (ducky.mm.MemoryController) – Controller that owns this page.
- index (int) – Serial number of this page.
-
read_u16
(offset)[source]¶ Read word.
This operation is implemented by child classes.
Parameters: offset (int) – offset of requested word. Return type: int
-
read_u32
(offset)[source]¶ Read longword.
This operation is implemented by child classes.
Parameters: offset (int) – offset of requested longword. Return type: int
-
read_u8
(offset)[source]¶ Read byte.
This operation is implemented by child classes.
Parameters: offset (int) – offset of requested byte. Return type: int
-
save_state
(parent)[source]¶ Create state of this page, and attach it to snapshot tree.
Parameters: parent (ducky.snapshot.SnapshotNode) – Parent snapshot node.
-
write_u16
(offset, value)[source]¶ Write word.
This operation is implemented by child classes.
Parameters: - offset (int) – offset of requested word.
- value (int) – value to write into memory.
-
class
ducky.mm.
MemoryPageState
(*args, **kwargs)[source]¶ Bases:
ducky.snapshot.SnapshotNode
-
class
ducky.mm.
MemoryRegion
(mc, name, address, size, flags)[source]¶ Bases:
ducky.interfaces.ISnapshotable
,object
-
region_id
= 0¶
-
-
class
ducky.mm.
MemoryRegionState
[source]¶ Bases:
ducky.snapshot.SnapshotNode
-
class
ducky.mm.
MemoryState
[source]¶ Bases:
ducky.snapshot.SnapshotNode
-
ducky.mm.
PAGE_SIZE
= 256¶ Size of memory page, in bytes.
ducky.patch module¶
ducky.profiler module¶
This module provides support for profiling the virtual machine (machine profilers) and running programs (code profilers). Wrappers for python’s deterministic profilers, and simple statistical profiler of running code are available for usage thoughout the ducky sources.
cProfile
is the prefered choice of machine profiling backend, with
profile
is used as a backup option.
Beware, each thread needs its own profiler instance. These instances can be acquired from ProfilerStore class which handles saving their data when virtual machine exits.
To simplify the usage of profilers in ducky sources in case when user does not
need profiling, I chose to provide classes with the same API but these classes
does not capture any data. These are called dummy profilers, as opposed to
the real ones. Both kinds mimic API of profile.Profile
- the
real machine profiler is profile.Profile
object.
-
class
ducky.profiler.
DummyCPUCoreProfiler
(core, frequency=17)[source]¶ Bases:
object
Dummy code profiler class. Base class for all code profilers.
Parameters: - core (ducky.cpu.CPUCore) – core this profiler captures data from.
- frequency (int) – sampling frequency, given as an instruction count.
-
class
ducky.profiler.
DummyMachineProfiler
(*args, **kwargs)[source]¶ Bases:
object
Dummy machine profiler. Does absolutely nothing.
-
class
ducky.profiler.
ProfilerStore
[source]¶ Bases:
object
This class manages profiler instances. When in need of a profiler (e.g. in a new thread) get one by calling proper method of ProfilerStore object.
-
get_core_profiler
(core)[source]¶ Create new code profiler.
Return type: DummyCPUCoreProfiler
-
get_machine_profiler
()[source]¶ Create and return new machine profiler.
Returns: new machine profiler.
-
-
class
ducky.profiler.
RealCPUCoreProfiler
(core)[source]¶ Bases:
ducky.profiler.DummyCPUCoreProfiler
Real code profiler. This class actually does collect data.
-
ducky.profiler.
STORE
= <ducky.profiler.ProfilerStore object>¶ Main profiler store
ducky.reactor module¶
This module provides simple reactor core that runs each of registered tasks at least once during one iteration of its internal loop.
There are two different kinds of objects that reactor manages:
- task - it’s called periodicaly, at least once in each reactor loop iteration
- event - asynchronous events are queued and executed before running any tasks. If there are no runnable tasks, reactor loop waits for incomming events.
-
class
ducky.reactor.
CallInReactorTask
(fn, *args, **kwargs)[source]¶ Bases:
ducky.interfaces.IReactorTask
This task request running particular function during the reactor loop. Useful for planning future work, and for running tasks in reactor’s thread.
Parameters: - fn – callback to fire.
- args – arguments for callback.
- kwargs – keyword arguments for callback.
-
class
ducky.reactor.
FDCallbacks
(on_read, on_write, on_error)¶ Bases:
tuple
-
on_error
¶ Alias for field number 2
-
on_read
¶ Alias for field number 0
-
on_write
¶ Alias for field number 1
-
-
class
ducky.reactor.
Reactor
(machine)[source]¶ Bases:
object
Main reactor class.
-
add_call
(fn, *args, **kwargs)[source]¶ Enqueue function call. Function will be called in reactor loop.
-
add_fd
(fd, on_read=None, on_write=None, on_error=None)[source]¶ Register file descriptor with reactor. File descriptor will be checked for read/write/error posibilities, and appropriate callbacks will be fired.
No arguments are passed to callbacks.
Parameters: - fd (int) – file descriptor.
- on_read – function that will be called when file descriptor is available for reading.
- on_write – function that will be called when file descriptor is available for write.
- on_error – function that will be called when error state raised on file descriptor.
-
remove_fd
(fd)[source]¶ Unregister file descriptor. It will no longer be checked by its main loop.
Parameters: fd (int) – previously registered file descriptor.
-
run
()[source]¶ Starts reactor loop. Enters endless loop, calling runnable tasks and events, and - in case there are no runnable tasks - waits for new events.
When there are no tasks managed by reactor, loop quits.
-
task_runnable
(task)[source]¶ If not yet marked as such, task is marked as runnable, and its
run()
method will be called every iteration of reactor’s main loop.
-
task_suspended
(task)[source]¶ If runnable, task is marked as suspended, not runnable, and it will no longer be ran by reactor. It’s still registered, so reactor’s main loop will not quit, and task can be later easily re-enabled by calling
ducky.reactor.Reactor.task_runnable()
.
-
-
class
ducky.reactor.
RunInIntervalTask
(ticks, fn, *args, **kwargs)[source]¶ Bases:
ducky.interfaces.IReactorTask
This task will run its callback every
ticks
iterations of reactor’s main loop.Parameters: - ticks (int) – number of main loop iterations between two callback calls.
- args – arguments for callback.
- kwargs – keyword arguments for callback.
-
class
ducky.reactor.
SelectTask
(machine, fds, *args, **kwargs)[source]¶ Bases:
ducky.interfaces.IReactorTask
Private task, serving as a single point where
select
syscall is being executed. When a subsystem is interested in IO on a file descriptor, such file descriptor should be set as non-blocking, and then registered with reactor - it’s not viable to placeselect
calls everywhere in different drivers. This task takes list of registered file descriptors, checks for possible IO oportunities, and fires callbacks accordingly.Parameters: - machine (ducky.machine.Machine) – VM this task (and reactor) belongs to.
- fds (dict) – dictionary, where keys are descriptors, and values are lists of their callbacks.
-
add_fd
(fd, on_read=None, on_write=None, on_error=None)[source]¶ Register file descriptor with reactor. File descriptor will be checked for read/write/error posibilities, and appropriate callbacks will be fired.
No arguments are passed to callbacks.
Parameters: - fd (int) – file descriptor.
- on_read – function that will be called when file descriptor is available for reading.
- on_write – function that will be called when file descriptor is available for write.
- on_error – function that will be called when error state raised on file descriptor.
ducky.snapshot module¶
-
class
ducky.snapshot.
CoreDumpFile
(logger, stream)[source]¶ Bases:
ducky.util.BinaryFile
ducky.streams module¶
Streams represent basic IO objects, used by devices for reading or writing (streams) of data.
Stream
object encapsulates an actual IO object - file
-like stream,
raw file descriptor, or even something completely different. Stream
classes
then provide basic IO methods for moving data to and from stream, shielding
user from implementation details, like Python2/Python3 differencies.
-
class
ducky.streams.
FDInputStream
(machine, fd, **kwargs)[source]¶ Bases:
ducky.streams.InputStream
-
class
ducky.streams.
FDOutputStream
(machine, fd, **kwargs)[source]¶ Bases:
ducky.streams.OutputStream
-
class
ducky.streams.
FileInputStream
(machine, f, **kwargs)[source]¶ Bases:
ducky.streams.InputStream
-
class
ducky.streams.
FileOutputStream
(machine, f, **kwargs)[source]¶ Bases:
ducky.streams.OutputStream
-
class
ducky.streams.
InputStream
(machine, desc, stream=None, fd=None, close=True, allow_close=True)[source]¶ Bases:
ducky.streams.Stream
-
class
ducky.streams.
MethodInputStream
(machine, desc, **kwargs)[source]¶ Bases:
ducky.streams.InputStream
-
class
ducky.streams.
MethodOutputStream
(machine, desc, **kwargs)[source]¶ Bases:
ducky.streams.OutputStream
-
class
ducky.streams.
OutputStream
(machine, desc, stream=None, fd=None, close=True, allow_close=True)[source]¶ Bases:
ducky.streams.Stream
-
class
ducky.streams.
StderrStream
(machine)[source]¶ Bases:
ducky.streams.OutputStream
-
class
ducky.streams.
StdinStream
(machine, **kwargs)[source]¶ Bases:
ducky.streams.InputStream
-
class
ducky.streams.
StdoutStream
(machine)[source]¶ Bases:
ducky.streams.OutputStream
-
class
ducky.streams.
Stream
(machine, desc, stream=None, fd=None, close=True, allow_close=True)[source]¶ Bases:
object
Abstract base class of all streams.
Parameters: - machine – parent :py:class`ducky.machine.Machine` object.
- desc – description of stream. This is a short, string representation of the stream.
- stream –
file
-like stream that provides IO method (read()
orwrite
). If it is set, it is preferred IO object. - fd (int) – raw file descriptor.
stream
takes precedence, otherwise this file descriptor is used. - close (bool) – if
True
, and ifstream
has aclose()
method, stream will provideclose()
method that will close the underlayingfile
-like object.True
by default. - allow_close (bool) – if not
True
, stream’sclose()
method will not close underlying IO resource.True
by default.
-
close
()[source]¶ This method will close the stream. If
allow_close
flag is not set toTrue
, nothing will happen. If the stream wasn’t created withclose
set toTrue
, nothing will happen. If the wrapped IO resource does not haveclose()
method, nothing will happen.
-
has_fd
()[source]¶ Check if stream has raw file descriptor. File descriptors can be checked for IO availability by reactor’s polling task.
Return type: bool Returns: True
when stream has file descriptor.
-
read
(size=None)[source]¶ Read data from stream.
Parameters: size (int) – if set, read at maximum size
bytes.Return type: bytearray
(Python2),bytes
(Python3)Returns: read data, of maximum lenght of size
,None
when there are no available data, or empty string in case of EOF.
-
register_with_reactor
(reactor, **kwargs)[source]¶ Called by owner to register the stream with reactor’s polling service.
See
ducky.reactor.Reactor.add_fd()
for keyword arguments.Parameters: reactor (ducky.reactor.Reactor) – reactor instance to register with.
-
unregister_with_reactor
(reactor)[source]¶ Called by owner to unregister the stream with reactor’s polling service, e.g. when stream is about to be closed.
Parameters: reactor (ducky.reactor.Reactor) – reactor instance to unregister from.
ducky.tools package¶
Submodules¶
ducky.tools.as module¶
ducky.tools.cc module¶
ducky.tools.coredump module¶
ducky.tools.defs module¶
ducky.tools.img module¶
ducky.tools.ld module¶
ducky.tools.objdump module¶
ducky.tools.profile module¶
ducky.tools.vm module¶
-
class
ducky.tools.vm.
DuckyProtocol
(logger, options, config)[source]¶ Bases:
autobahn.twisted.websocket.WebSocketServerProtocol
Protocol handling communication between VM and remote terminal emulator.
Parameters: - logger (logging.Logger) –
Logger
instanceto use for logging. - options – command-line options, as returned by option parser.
- config (ducky.config.MachineConfig) – VM configuration.
-
onClose
(wasClean, code, reason)[source]¶ Called when connection ends. Tell VM to halt, and wait for its thread to finish. Then, print some VM stats.
-
onMessage
(payload, isBinary)[source]¶ Called when new data arrived from client. Feeds the data to VM’s input stream.
See
autobahn.twisted.websocket.WebSocketServerProtocol.onMessage()
.
- logger (logging.Logger) –
-
class
ducky.tools.vm.
DuckySocketServerFactory
(logger, options, config, *args, **kwargs)[source]¶ Bases:
autobahn.twisted.websocket.WebSocketServerFactory
-
class
ducky.tools.vm.
WSInputStream
(protocol, *args, **kwargs)[source]¶ Bases:
ducky.streams.InputStream
Websocket input stream, receiving bytes from opened websocket, and pushing them to keyboard frontend device.
Stream has an internal LIFO buffer that is being fed by protocol, and consumed by VM frontend device.
Parameters: protocol (DuckyProtocol) – protocol instance with opened websocket. -
enqueue
(buff)[source]¶ Called by protocol instance, to add newly received data to stream’s buffer.
Parameters: buff (bytearray) – recerived bytes.
-
-
class
ducky.tools.vm.
WSOutputStream
(protocol, *args, **kwargs)[source]¶ Bases:
ducky.streams.OutputStream
Websocket output stream, receiving bytes from TTY frontend, and pushing them to protocol’s socket.
Parameters: protocol (DuckyProtocol) – protocol instance with opened websocket.
-
ducky.tools.vm.
process_config_options
(logger, options, config_file=None, set_options=None, add_options=None, enable_devices=None, disable_devices=None)[source]¶ Load VM config file, and apply all necessary changes, as requested by command-line options.
Parameters: - logger (logging.Logger) –
Logger
instance to use for logging. - options – command-line options, as returned by option parser.
- config_file (string) – path to configuration file.
Return type: Returns: VM configuration.
- logger (logging.Logger) –
ducky.util module¶
-
class
ducky.util.
BinaryFile
(logger, stream)[source]¶ Bases:
object
Base class of all classes that represent “binary” files - binaries, core dumps. It provides basic methods for reading and writing structures.
-
class
ducky.util.
LRUCache
(logger, size, *args, **kwargs)[source]¶ Bases:
collections.OrderedDict
Simple LRU cache, based on
OrderedDict
, with limited size. When limit is reached, the least recently inserted item is removed.Parameters: - logger (logging.Logger) – logger object instance should use for logging.
- size (int) – maximal number of entries allowed.
-
class
ducky.util.
StringTable
[source]¶ Bases:
object
Simple string table, used by many classes operating with files (core, binaries, ...). String can be inserted into table and read, each has its starting offset and its end is marked with null byte ().
Thsi is a helper class - it makes working with string, e.g. section and symbol names, much easier.