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 assembly 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
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__
'3.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. PyPy is also supported, though only its
implementation of Python2.
“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/hello-world
directory. If you check it out, it’s
a plain and simple assembler:
#include <arch/tty.hs>
.data
.type stack, space, 64
.type message, string, "Hello, world!"
.text
main:
la sp, stack
add sp, 64
la r0, message
call writesn
hlt 0x00
writesn:
// > r0: string address
// ...
// r0: port
// r1: current byte
// r2: string ptr
push r1
push r2
mov r2, r0
li r0, TTY_MMIO_ADDRESS
add r0, TTY_MMIO_DATA
.__writesn_loop:
lb r1, r2
bz .__writesn_write_nl
stb r0, r1
inc r2
j .__writesn_loop
.__writesn_write_nl:
// \n
li r1, 0x0000000A
stb r0, r1
// \r
li r1, 0x0000000D
stb r0, r1
li r0, 0x00000000
pop r2
pop r1
ret
It’s a little bit more structured that necessary, just for educational purposes.
Binary¶
To run this code, we have to create a binary of it. Of course, there are tools for this very common goal:
ducky-as -i examples/hello-world/hello-world.s -o examples/hello-world/hello-world.o
This command will translate source code to an object file which contains
instructions and other necessary resources for machine to run it. 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/hello-world.o
[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]
As you can see, object file contains instructions, some additional data, list of symbols, and some more, 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 yet 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 other sections from all source object
files, and updates addresses used by instructions to retrieve data and to
perform jumps. You can inspect the resulting binary file using objdump
tool
as well:
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 file, 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 --set-option=bootloader:file=examples/hello-world/hello-world
There are two command-line options:
--machine-config
tells VM where to find its configuration file,--set-option
modifies this configuration; this particular instance tells VM to setfile
option in sectionbootloader
to path of our freshly built binary,examples/hello-world/hello-world
. Since I run examples during testing process, their config files lack this option since it changes all the time.
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 16, 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.
And that’s it.
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
tor29
are general purpose registers -r31
is reserved, and used as a stack pointer register,SP
- contains address of the last value pushed on stack -r30
is reserved, and used as a frame pointer register,FP
- contains content ofSP
in time of the lastcall
orint
instructionflags
register
Flags register¶
flags
register can be considered as read-only value, since it is not possible to modify it using common bit operations or arithmetic instructions. However, its content reflect outcomes of executed instructions, therefore it is possible e.g. to modify it content using comparison instructions. It is also possible to inspect and modify it in exception service routine, where pre-exception flags
are stored on the stack (and loaded when ESR ends).
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 sets. 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.
Ducky instruction set¶
- basic data unit is a word - 4 bytes, 32 bits. Other units are short - 2 bytes, 16 bits - and byte - 1 byte, 8 bits. 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)
- unless said otherwise, destination operand is the first one
- 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 tor29
- 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- immediate values are encoded in the instructions, therefore such value cannot have full 32-bit width. Each instruction should indicate the maximal width of immediate value that can be safely encoded, should you require grater values, please see
li
andliu
instructions
Several instructions transfer control to other parts of program, with possibility of returning back to the 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 is always stored in the first operand.
and rA, (rB|<value>)
not rA
or rA, (rB|<value>)
shiftl rA, (rB|<value>)
shiftr rA, (rB|<value>)
shiftrs 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 |
e = 1 |
bne |
e = 0 |
bs |
s = 1 |
bns |
s = 0 |
bz |
z = 1 |
bnz |
z = 0 |
bo |
o = 1 |
bno |
o = 0 |
bg |
e = 0 and s = 0 |
bge |
e = 1 or s = 0 |
bl |
e = 0 and s = 1 |
ble |
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.
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 inEVT
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
- delivery of hardware interrupts is disabled
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
stw {address}, rA
sts {address}, rA
- store lower 2 bytes of rA
stb {addres}, rA
- store lower byte of rA
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
.
Control coprocessor¶
Control coprocessor (CC) is a coprocessor dedicated to control various runtime properties of CPU core. Using ctr
and ctw
instructions it is possible to inspect and modify these properties.
Control registers¶
CR0¶
cr0
register contains so-called CPUID
value which intendifies location of this CPU core in global CPU topology.
- upper 16 bits contain index number of CPU this core belongs to
- lower 16 bits contain index number of this core in the context of its parent CPU
There’s always core with CPUID
0x00000000
, since there’s always at least one core present.
This register is read-only.
CR1¶
cr1
register contains Exception Vector Table address for this core. Be aware that any address is accepted, no aligment or any other restrictions are applied.
CR2¶
cr2
register contains page table address for this core. Be aware that any address is accepted, no aligment or any other restrictions are applied.
CR3¶
cr3
register provides access to several flags that modify behavior of CPU core.
Mask | Flag | Usage |
0x00 | pt_enabled |
If set, MMU consults all memory accesses with page tables. |
0x01 | jit |
If set, JIT optimizations are enabled. |
0x02 | vmdebug |
If set, VM will produce huge amount of debugging logs. |
Note
jit
flag is read-only. It is controlled by options passed to Ducky when VM was created, and cannot be changed in runtime.
Note
vmdebug
flag is shared between all existing cores. Changing it on one core affects immediately all other cores.
Note
vmdebug
flag will not produce any debugging output if debug mode was disabled e.g. by not passing -d
option to ducky-vm
tool. If debug mode was allowed, changing this flag will control log level of VM.
Exception Vector Table¶
Exception vector table (EVT) is located in main memory, by default at address 0x00000000
, and provides core with routines that can help resolve some of exceptional states core can run into.
EVT
address can be set per CPU core, see CR1.
EVT
is 256 bytes - 1 memory page - long, providing enough space for 32 entries. Typically, lower 16 entries are reserved for hardware interrupts, provided by devices, and upper
16 entries lead to software routines that deal with exceptions, and provide additional functionality for running code in form of software interrupts.
Entry format¶
IP - 32 bits |
SP - 32 bits |
When CPU is interrupted - by hardware (device generates IRQ) or software (exception is detected, or program executes int
instruction) interrupt - corresponding entry is located in EVT
, using interrupt ID as an index.
Hardware Description Table¶
Hardware Description Table (HDT) is located in main memory, by default at address 0x00000100
, and hardware setup of the machine.
Memory¶
Memory model¶
- the full addressable memory is 4 GB, since the address bus is 32-bit wide, 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¶
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
EVT
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 EVT
, 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
¶
EVT 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
¶
EVT 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
was 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, symbol 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.
-b, --blob
¶
Create object file wrapping a binary blob. Such file then contains the data from input file, encoded as ASCII data, with several symbols allowing other code to access this data.
-B BLOB_FLAGS, --blob-flags=BLOB_FLAGS
¶
Flags of blob section. Syntax of assembly .section
directive is accepted.
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.
--jit
¶
Enable JIT - more dense implementation of Ducky instructions is used. Result is higher execution speed of each instruction, however it removes many debugging code. It may be difficult to debug instruction execution even with -d
option enabled.
Glossary¶
- binary
- Binary is the final piece in the process
- bootloader
- Bootloader, for purposes of this documentation, means virtually any piece of bytecode. It gains its “bootloader-like” property by the fact that it’s the first piece of code that’s executed by CPU core.
- EVT
- Exception Vector Table
- HDT
- Hardware Description Table
- linker
Linker takes an object file (or more, or even an archive), and creates a binary by merging relevant sections and by replacing symbolic references with final offsets.
ld provides this functionality.
- machine
- For a long time, Ducky existed only as an software simulator. But, since I got that great idea about getting me a simple FPGA and learn VHDL, this may no longer be true. So, when I write about machine, I mean both software simulator (VM) and hardware materialization of Ducky SoC.
- object file
- Object file is a file containing compiled code in a form of distinct sections of instructions, data and other necessary resources. Despite sharing their format with binary file, object files are usualy not executable because pretty much no instructions that address memory contain correct offsets, and refer to the locations using symbols. Final offsets are calculated and fixed by a linker.
- VM
- Virtual Machine. For a long time, the only existing Ducky implementation.
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 may 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 bymmap.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 ofducky.boot.MMapArea
instances, and if such area was opened as shared, every change in the content of its pages will reflect onto the content of an 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. -
_get_py2
(offset)[source]¶ Read one byte from page.
Parameters: offset (int) – offset of the requested byte. Return type: int
-
_get_py3
(offset)[source]¶ Read one byte from page.
Parameters: offset (int) – offset of the requested byte. Return type: int
-
_put_py2
(offset, b)[source]¶ Write one byte to page.
Parameters: - offset (int) – offset of the modified byte.
- b (int) – new value of the modified byte.
-
_put_py3
(offset, b)[source]¶ Write one byte to page.
Parameters: - offset (int) – offset of the modified byte.
- b (int) – new value of the modified byte.
-
-
class
ducky.boot.
ROMLoader
(machine)[source]¶ Bases:
ducky.interfaces.IMachineWorker
This class provides methods for loading all necessary pieces into VM’s memory. These methods are called in VM’s boot phase.
-
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_bootloader
(filepath, base=None)[source]¶ Load bootloader into main memory.
In the world of a real hardware, bootloader binary would be transformed into an image, and then “burned” in some form into the memory - main, or some kind of ROM from which it’d be loaded into main memory at the very beginning of boot process.
Parameters: - filepath (str) – path to bootloader binary.
- base (u32_t) – address of the first byte of bootloader in memory.
By default,
ducky.boot.DEFAULT_BOOTLOADER_ADDRESS
is used.
-
setup_hdt
()[source]¶ Initialize memory area containing Hardware Description Table.
If VM config file specifies
HDT
image file, it is loaded, otherwise HDT is constructed for the actual configuration, and then it’s 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 (str) –
HDT
image to load. If not set,HDT
is constructed for the actual VM’s configuration.
- machine.hdt-address (u32_t) – Base address of
-
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.
-
_MachineConfig__count
(prefix)¶
-
_MachineConfig__count_breakpoints
()¶
-
_MachineConfig__count_devices
()¶
-
_MachineConfig__count_mmaps
()¶
-
_MachineConfig__sections_with_prefix
(prefix)¶
-
_boolean_states
= {'1': True, 'on': True, 'false': False, '0': False, 'off': False, 'yes': True, 'no': False, 'true': True}¶
-
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.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
= 0¶
-
CR1
= 1¶
-
CR2
= 2¶
-
CR3
= 3¶
-
_member_map_
= OrderedDict([('CR0', <ControlRegisters.CR0: 0>), ('CR1', <ControlRegisters.CR1: 1>), ('CR2', <ControlRegisters.CR2: 2>), ('CR3', <ControlRegisters.CR3: 3>)])¶
-
_member_names_
= ['CR0', 'CR1', 'CR2', 'CR3']¶
-
_member_type_
¶ alias of
int
-
_value2member_map_
= {0: <ControlRegisters.CR0: 0>, 1: <ControlRegisters.CR1: 1>, 2: <ControlRegisters.CR2: 2>, 3: <ControlRegisters.CR3: 3>}¶
-
-
class
ducky.cpu.coprocessor.control.
CoreFlags
[source]¶ Bases:
ducky.util.Flags
-
_flags
= ['pt_enabled', 'jit', 'vmdebug']¶
-
_labels
= 'PJV'¶
-
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
= 32¶
-
operands
= ['']¶
-
-
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
= 31¶
-
operands
= ['']¶
-
-
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
= 11¶
-
operands
= ['']¶
-
-
class
ducky.cpu.coprocessor.math_copro.
DROP
(instruction_set)[source]¶ Bases:
ducky.cpu.coprocessor.math_copro.Descriptor_MATH
-
mnemonic
= 'drop'¶
-
opcode
= 23¶
-
operands
= ['']¶
-
-
class
ducky.cpu.coprocessor.math_copro.
DUP
(instruction_set)[source]¶ Bases:
ducky.cpu.coprocessor.math_copro.Descriptor_MATH
-
mnemonic
= 'dup'¶
-
opcode
= 20¶
-
operands
= ['']¶
-
-
class
ducky.cpu.coprocessor.math_copro.
DUP2
(instruction_set)[source]¶ Bases:
ducky.cpu.coprocessor.math_copro.Descriptor_MATH
-
mnemonic
= 'dup2'¶
-
opcode
= 21¶
-
operands
= ['']¶
-
-
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.errors.CoprocessorError
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.errors.CoprocessorError
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
= 30¶
-
operands
= ['']¶
-
-
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
= 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
= 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
= 4¶
-
operands
= ['r']¶
-
-
class
ducky.cpu.coprocessor.math_copro.
MODL
(instruction_set)[source]¶ Bases:
ducky.cpu.coprocessor.math_copro.Descriptor_MATH
-
mnemonic
= 'modl'¶
-
opcode
= 12¶
-
operands
= ['']¶
-
-
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
= 10¶
-
operands
= ['']¶
-
-
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>, <ducky.cpu.coprocessor.math_copro.INCL object>, <ducky.cpu.coprocessor.math_copro.DECL object>, <ducky.cpu.coprocessor.math_copro.MULL object>, <ducky.cpu.coprocessor.math_copro.DIVL object>, <ducky.cpu.coprocessor.math_copro.MODL object>, <ducky.cpu.coprocessor.math_copro.UDIVL object>, <ducky.cpu.coprocessor.math_copro.UMODL object>, <ducky.cpu.coprocessor.math_copro.SYMDIVL object>, <ducky.cpu.coprocessor.math_copro.SYMMODL object>, <ducky.cpu.coprocessor.math_copro.DUP object>, <ducky.cpu.coprocessor.math_copro.DUP2 object>, <ducky.cpu.coprocessor.math_copro.SWP object>, <ducky.cpu.coprocessor.math_copro.DROP object>, <ducky.cpu.coprocessor.math_copro.PUSHW object>, <ducky.cpu.coprocessor.math_copro.SAVEW object>, <ducky.cpu.coprocessor.math_copro.POPW object>, <ducky.cpu.coprocessor.math_copro.LOADW object>, <ducky.cpu.coprocessor.math_copro.POPUW object>, <ducky.cpu.coprocessor.math_copro.LOADUW object>, <ducky.cpu.coprocessor.math_copro.PUSHL object>, <ducky.cpu.coprocessor.math_copro.SAVE object>, <ducky.cpu.coprocessor.math_copro.POPL object>, <ducky.cpu.coprocessor.math_copro.LOAD object>, <ducky.cpu.instructions.SIS object>]¶
-
opcode_desc_map
= {<MathCoprocessorOpcodes.POPW: 0>: <ducky.cpu.coprocessor.math_copro.POPW object>, <MathCoprocessorOpcodes.POPUW: 1>: <ducky.cpu.coprocessor.math_copro.POPUW object>, <MathCoprocessorOpcodes.PUSHW: 2>: <ducky.cpu.coprocessor.math_copro.PUSHW object>, <MathCoprocessorOpcodes.SAVEW: 3>: <ducky.cpu.coprocessor.math_copro.SAVEW object>, <MathCoprocessorOpcodes.LOADW: 4>: <ducky.cpu.coprocessor.math_copro.LOADW object>, <MathCoprocessorOpcodes.LOADUW: 5>: <ducky.cpu.coprocessor.math_copro.LOADUW object>, <MathCoprocessorOpcodes.POPL: 6>: <ducky.cpu.coprocessor.math_copro.POPL object>, <MathCoprocessorOpcodes.SAVE: 7>: <ducky.cpu.coprocessor.math_copro.SAVE object>, <MathCoprocessorOpcodes.PUSHL: 8>: <ducky.cpu.coprocessor.math_copro.PUSHL object>, <MathCoprocessorOpcodes.LOAD: 9>: <ducky.cpu.coprocessor.math_copro.LOAD object>, <MathCoprocessorOpcodes.MULL: 10>: <ducky.cpu.coprocessor.math_copro.MULL object>, <MathCoprocessorOpcodes.DIVL: 11>: <ducky.cpu.coprocessor.math_copro.DIVL object>, <MathCoprocessorOpcodes.MODL: 12>: <ducky.cpu.coprocessor.math_copro.MODL object>, <MathCoprocessorOpcodes.SYMDIVL: 13>: <ducky.cpu.coprocessor.math_copro.SYMDIVL object>, <MathCoprocessorOpcodes.SYMMODL: 14>: <ducky.cpu.coprocessor.math_copro.SYMMODL object>, <MathCoprocessorOpcodes.UDIVL: 15>: <ducky.cpu.coprocessor.math_copro.UDIVL object>, <MathCoprocessorOpcodes.UMODL: 16>: <ducky.cpu.coprocessor.math_copro.UMODL object>, <MathCoprocessorOpcodes.DUP: 20>: <ducky.cpu.coprocessor.math_copro.DUP object>, <MathCoprocessorOpcodes.DUP2: 21>: <ducky.cpu.coprocessor.math_copro.DUP2 object>, <MathCoprocessorOpcodes.SWP: 22>: <ducky.cpu.coprocessor.math_copro.SWP object>, <MathCoprocessorOpcodes.DROP: 23>: <ducky.cpu.coprocessor.math_copro.DROP object>, <MathCoprocessorOpcodes.INCL: 30>: <ducky.cpu.coprocessor.math_copro.INCL object>, <MathCoprocessorOpcodes.DECL: 31>: <ducky.cpu.coprocessor.math_copro.DECL object>, <MathCoprocessorOpcodes.ADDL: 32>: <ducky.cpu.coprocessor.math_copro.ADDL object>, <DuckyOpcodes.SIS: 63>: <ducky.cpu.instructions.SIS object>}¶
-
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.POPL: 6>: <class 'ducky.cpu.instructions.EncodingR'>, <MathCoprocessorOpcodes.SAVE: 7>: <class 'ducky.cpu.instructions.EncodingR'>, <MathCoprocessorOpcodes.PUSHL: 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
= 32¶
-
DECL
= 31¶
-
DIVL
= 11¶
-
DROP
= 23¶
-
DUP
= 20¶
-
DUP2
= 21¶
-
INCL
= 30¶
-
LOAD
= 9¶
-
LOADUW
= 5¶
-
LOADW
= 4¶
-
MODL
= 12¶
-
MULL
= 10¶
-
POPL
= 6¶
-
POPUW
= 1¶
-
POPW
= 0¶
-
PUSHL
= 8¶
-
PUSHW
= 2¶
-
SAVE
= 7¶
-
SAVEW
= 3¶
-
SIS
= 63¶
-
SWP
= 22¶
-
SYMDIVL
= 13¶
-
SYMMODL
= 14¶
-
UDIVL
= 15¶
-
UMODL
= 16¶
-
_member_map_
= OrderedDict([('POPW', <MathCoprocessorOpcodes.POPW: 0>), ('POPUW', <MathCoprocessorOpcodes.POPUW: 1>), ('PUSHW', <MathCoprocessorOpcodes.PUSHW: 2>), ('SAVEW', <MathCoprocessorOpcodes.SAVEW: 3>), ('LOADW', <MathCoprocessorOpcodes.LOADW: 4>), ('LOADUW', <MathCoprocessorOpcodes.LOADUW: 5>), ('POPL', <MathCoprocessorOpcodes.POPL: 6>), ('SAVE', <MathCoprocessorOpcodes.SAVE: 7>), ('PUSHL', <MathCoprocessorOpcodes.PUSHL: 8>), ('LOAD', <MathCoprocessorOpcodes.LOAD: 9>), ('MULL', <MathCoprocessorOpcodes.MULL: 10>), ('DIVL', <MathCoprocessorOpcodes.DIVL: 11>), ('MODL', <MathCoprocessorOpcodes.MODL: 12>), ('SYMDIVL', <MathCoprocessorOpcodes.SYMDIVL: 13>), ('SYMMODL', <MathCoprocessorOpcodes.SYMMODL: 14>), ('UDIVL', <MathCoprocessorOpcodes.UDIVL: 15>), ('UMODL', <MathCoprocessorOpcodes.UMODL: 16>), ('DUP', <MathCoprocessorOpcodes.DUP: 20>), ('DUP2', <MathCoprocessorOpcodes.DUP2: 21>), ('SWP', <MathCoprocessorOpcodes.SWP: 22>), ('DROP', <MathCoprocessorOpcodes.DROP: 23>), ('INCL', <MathCoprocessorOpcodes.INCL: 30>), ('DECL', <MathCoprocessorOpcodes.DECL: 31>), ('ADDL', <MathCoprocessorOpcodes.ADDL: 32>), ('SIS', <MathCoprocessorOpcodes.SIS: 63>)])¶
-
_member_names_
= ['POPW', 'POPUW', 'PUSHW', 'SAVEW', 'LOADW', 'LOADUW', 'POPL', 'SAVE', 'PUSHL', 'LOAD', 'MULL', 'DIVL', 'MODL', 'SYMDIVL', 'SYMMODL', 'UDIVL', 'UMODL', 'DUP', 'DUP2', 'SWP', 'DROP', 'INCL', 'DECL', 'ADDL', 'SIS']¶
-
_member_type_
¶ alias of
int
-
_value2member_map_
= {0: <MathCoprocessorOpcodes.POPW: 0>, 1: <MathCoprocessorOpcodes.POPUW: 1>, 2: <MathCoprocessorOpcodes.PUSHW: 2>, 3: <MathCoprocessorOpcodes.SAVEW: 3>, 4: <MathCoprocessorOpcodes.LOADW: 4>, 5: <MathCoprocessorOpcodes.LOADUW: 5>, 6: <MathCoprocessorOpcodes.POPL: 6>, 7: <MathCoprocessorOpcodes.SAVE: 7>, 8: <MathCoprocessorOpcodes.PUSHL: 8>, 9: <MathCoprocessorOpcodes.LOAD: 9>, 10: <MathCoprocessorOpcodes.MULL: 10>, 11: <MathCoprocessorOpcodes.DIVL: 11>, 12: <MathCoprocessorOpcodes.MODL: 12>, 13: <MathCoprocessorOpcodes.SYMDIVL: 13>, 14: <MathCoprocessorOpcodes.SYMMODL: 14>, 15: <MathCoprocessorOpcodes.UDIVL: 15>, 16: <MathCoprocessorOpcodes.UMODL: 16>, 20: <MathCoprocessorOpcodes.DUP: 20>, 21: <MathCoprocessorOpcodes.DUP2: 21>, 22: <MathCoprocessorOpcodes.SWP: 22>, 23: <MathCoprocessorOpcodes.DROP: 23>, 30: <MathCoprocessorOpcodes.INCL: 30>, 31: <MathCoprocessorOpcodes.DECL: 31>, 32: <MathCoprocessorOpcodes.ADDL: 32>, 63: <MathCoprocessorOpcodes.SIS: 63>}¶
-
-
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.
POPL
(instruction_set)[source]¶ Bases:
ducky.cpu.coprocessor.math_copro.Descriptor_MATH
Pop the
long
from data stack, and make it new TOS.-
mnemonic
= 'popl'¶
-
opcode
= 6¶
-
operands
= ['']¶
-
-
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
= 1¶
-
operands
= ['']¶
-
-
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
= 0¶
-
operands
= ['']¶
-
-
class
ducky.cpu.coprocessor.math_copro.
PUSHL
(instruction_set)[source]¶ Bases:
ducky.cpu.coprocessor.math_copro.Descriptor_MATH
Push the TOS on the data stack.
-
mnemonic
= 'pushl'¶
-
opcode
= 8¶
-
operands
= ['']¶
-
-
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
= 2¶
-
operands
= ['']¶
-
-
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
= 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
= 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
= 'swpl'¶
-
opcode
= 22¶
-
operands
= ['']¶
-
-
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
= 13¶
-
operands
= ['']¶
-
-
class
ducky.cpu.coprocessor.math_copro.
SYMMODL
(instruction_set)[source]¶ Bases:
ducky.cpu.coprocessor.math_copro.Descriptor_MATH
-
mnemonic
= 'symmodl'¶
-
opcode
= 14¶
-
operands
= ['']¶
-
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.instructions module¶
-
class
ducky.cpu.instructions.
ADD
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BINOP
-
mnemonic
= 'add'¶
-
opcode
= 28¶
-
operands
= ['r', 'ri']¶
-
-
class
ducky.cpu.instructions.
AND
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BITOP
-
mnemonic
= 'and'¶
-
opcode
= 34¶
-
operands
= ['r', 'ri']¶
-
-
class
ducky.cpu.instructions.
BE
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BRANCH
-
mnemonic
= 'be'¶
-
operands
= ['ri']¶
-
-
class
ducky.cpu.instructions.
BG
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BRANCH
-
mnemonic
= 'bg'¶
-
operands
= ['ri']¶
-
-
class
ducky.cpu.instructions.
BGE
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BRANCH
-
mnemonic
= 'bge'¶
-
operands
= ['ri']¶
-
-
class
ducky.cpu.instructions.
BL
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BRANCH
-
mnemonic
= 'bl'¶
-
operands
= ['ri']¶
-
-
class
ducky.cpu.instructions.
BLE
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BRANCH
-
mnemonic
= 'ble'¶
-
operands
= ['ri']¶
-
-
class
ducky.cpu.instructions.
BNE
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BRANCH
-
mnemonic
= 'bne'¶
-
operands
= ['ri']¶
-
-
class
ducky.cpu.instructions.
BNO
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BRANCH
-
mnemonic
= 'bno'¶
-
operands
= ['ri']¶
-
-
class
ducky.cpu.instructions.
BNS
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BRANCH
-
mnemonic
= 'bns'¶
-
operands
= ['ri']¶
-
-
class
ducky.cpu.instructions.
BNZ
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BRANCH
-
mnemonic
= 'bnz'¶
-
operands
= ['ri']¶
-
-
class
ducky.cpu.instructions.
BO
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BRANCH
-
mnemonic
= 'bo'¶
-
operands
= ['ri']¶
-
-
class
ducky.cpu.instructions.
BS
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BRANCH
-
mnemonic
= 'bs'¶
-
operands
= ['ri']¶
-
-
class
ducky.cpu.instructions.
BZ
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BRANCH
-
mnemonic
= 'bz'¶
-
operands
= ['ri']¶
-
-
class
ducky.cpu.instructions.
CALL
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._JUMP
-
mnemonic
= 'call'¶
-
opcode
= 15¶
-
operands
= ['ri']¶
-
-
class
ducky.cpu.instructions.
CAS
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor
-
mnemonic
= 'cas'¶
-
opcode
= 7¶
-
operands
= ['r', 'r', 'r']¶
-
-
class
ducky.cpu.instructions.
CLI
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor
-
mnemonic
= 'cli'¶
-
opcode
= 17¶
-
operands
= []¶
-
-
class
ducky.cpu.instructions.
CMP
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._CMP
-
mnemonic
= 'cmp'¶
-
opcode
= 47¶
-
operands
= ['r', 'ri']¶
-
-
class
ducky.cpu.instructions.
CMPU
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._CMP
-
mnemonic
= 'cmpu'¶
-
opcode
= 48¶
-
operands
= ['r', 'ri']¶
-
-
class
ducky.cpu.instructions.
CTR
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor_R_R
-
mnemonic
= 'ctr'¶
-
opcode
= 60¶
-
operands
= ['r', 'r']¶
-
-
class
ducky.cpu.instructions.
CTW
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor_R_R
-
mnemonic
= 'ctw'¶
-
opcode
= 61¶
-
operands
= ['r', 'r']¶
-
-
class
ducky.cpu.instructions.
DEC
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor_R
-
mnemonic
= 'dec'¶
-
opcode
= 27¶
-
operands
= ['r']¶
-
-
class
ducky.cpu.instructions.
DIV
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BINOP
-
mnemonic
= 'div'¶
-
opcode
= 31¶
-
operands
= ['r', 'ri']¶
-
-
class
ducky.cpu.instructions.
Descriptor
(instruction_set)[source]¶ Bases:
object
-
inst_aligned
= False¶
-
mnemonic
= None¶
-
opcode
= None¶
-
operands
= None¶
-
relative_address
= False¶
-
-
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_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>, <ducky.cpu.instructions.INT object>, <ducky.cpu.instructions.IPI object>, <ducky.cpu.instructions.RETINT object>, <ducky.cpu.instructions.CALL object>, <ducky.cpu.instructions.RET object>, <ducky.cpu.instructions.CLI object>, <ducky.cpu.instructions.STI object>, <ducky.cpu.instructions.HLT object>, <ducky.cpu.instructions.RST object>, <ducky.cpu.instructions.IDLE object>, <ducky.cpu.instructions.PUSH object>, <ducky.cpu.instructions.POP object>, <ducky.cpu.instructions.INC object>, <ducky.cpu.instructions.DEC object>, <ducky.cpu.instructions.ADD object>, <ducky.cpu.instructions.SUB object>, <ducky.cpu.instructions.CMP object>, <ducky.cpu.instructions.J object>, <ducky.cpu.instructions.AND object>, <ducky.cpu.instructions.OR object>, <ducky.cpu.instructions.XOR object>, <ducky.cpu.instructions.NOT object>, <ducky.cpu.instructions.SHL object>, <ducky.cpu.instructions.SHR object>, <ducky.cpu.instructions.SHRS object>, <ducky.cpu.instructions.LW object>, <ducky.cpu.instructions.LS object>, <ducky.cpu.instructions.LB object>, <ducky.cpu.instructions.LI object>, <ducky.cpu.instructions.LIU object>, <ducky.cpu.instructions.LA object>, <ducky.cpu.instructions.STW object>, <ducky.cpu.instructions.STS object>, <ducky.cpu.instructions.STB object>, <ducky.cpu.instructions.MOV object>, <ducky.cpu.instructions.SWP object>, <ducky.cpu.instructions.MUL object>, <ducky.cpu.instructions.DIV object>, <ducky.cpu.instructions.UDIV object>, <ducky.cpu.instructions.MOD object>, <ducky.cpu.instructions.CMPU object>, <ducky.cpu.instructions.CAS object>, <ducky.cpu.instructions.SIS object>, <ducky.cpu.instructions.BE object>, <ducky.cpu.instructions.BNE object>, <ducky.cpu.instructions.BZ object>, <ducky.cpu.instructions.BNZ object>, <ducky.cpu.instructions.BO object>, <ducky.cpu.instructions.BNO object>, <ducky.cpu.instructions.BS object>, <ducky.cpu.instructions.BNS object>, <ducky.cpu.instructions.BG object>, <ducky.cpu.instructions.BGE object>, <ducky.cpu.instructions.BL object>, <ducky.cpu.instructions.BLE object>, <ducky.cpu.instructions.SETE object>, <ducky.cpu.instructions.SETNE object>, <ducky.cpu.instructions.SETZ object>, <ducky.cpu.instructions.SETNZ object>, <ducky.cpu.instructions.SETO object>, <ducky.cpu.instructions.SETNO object>, <ducky.cpu.instructions.SETS object>, <ducky.cpu.instructions.SETNS object>, <ducky.cpu.instructions.SETG object>, <ducky.cpu.instructions.SETGE object>, <ducky.cpu.instructions.SETL object>, <ducky.cpu.instructions.SETLE object>, <ducky.cpu.instructions.SELE object>, <ducky.cpu.instructions.SELNE object>, <ducky.cpu.instructions.SELZ object>, <ducky.cpu.instructions.SELNZ object>, <ducky.cpu.instructions.SELO object>, <ducky.cpu.instructions.SELNO object>, <ducky.cpu.instructions.SELS object>, <ducky.cpu.instructions.SELNS object>, <ducky.cpu.instructions.SELG object>, <ducky.cpu.instructions.SELGE object>, <ducky.cpu.instructions.SELL object>, <ducky.cpu.instructions.SELLE object>, <ducky.cpu.instructions.LPM object>, <ducky.cpu.instructions.CTR object>, <ducky.cpu.instructions.CTW object>, <ducky.cpu.instructions.FPTC object>]¶
-
opcode_desc_map
= {<DuckyOpcodes.NOP: 0>: <ducky.cpu.instructions.NOP object>, <DuckyOpcodes.LW: 1>: <ducky.cpu.instructions.LW object>, <DuckyOpcodes.LS: 2>: <ducky.cpu.instructions.LS object>, <DuckyOpcodes.LB: 3>: <ducky.cpu.instructions.LB object>, <DuckyOpcodes.STW: 4>: <ducky.cpu.instructions.STW object>, <DuckyOpcodes.STS: 5>: <ducky.cpu.instructions.STS object>, <DuckyOpcodes.STB: 6>: <ducky.cpu.instructions.STB object>, <DuckyOpcodes.CAS: 7>: <ducky.cpu.instructions.CAS object>, <DuckyOpcodes.LA: 8>: <ducky.cpu.instructions.LA object>, <DuckyOpcodes.LI: 9>: <ducky.cpu.instructions.LI object>, <DuckyOpcodes.LIU: 10>: <ducky.cpu.instructions.LIU object>, <DuckyOpcodes.MOV: 11>: <ducky.cpu.instructions.MOV object>, <DuckyOpcodes.SWP: 12>: <ducky.cpu.instructions.SWP object>, <DuckyOpcodes.INT: 13>: <ducky.cpu.instructions.INT object>, <DuckyOpcodes.RETINT: 14>: <ducky.cpu.instructions.RETINT object>, <DuckyOpcodes.CALL: 15>: <ducky.cpu.instructions.CALL object>, <DuckyOpcodes.RET: 16>: <ducky.cpu.instructions.RET object>, <DuckyOpcodes.CLI: 17>: <ducky.cpu.instructions.CLI object>, <DuckyOpcodes.STI: 18>: <ducky.cpu.instructions.STI object>, <DuckyOpcodes.RST: 19>: <ducky.cpu.instructions.RST object>, <DuckyOpcodes.HLT: 20>: <ducky.cpu.instructions.HLT object>, <DuckyOpcodes.IDLE: 21>: <ducky.cpu.instructions.IDLE object>, <DuckyOpcodes.LPM: 22>: <ducky.cpu.instructions.LPM object>, <DuckyOpcodes.IPI: 23>: <ducky.cpu.instructions.IPI object>, <DuckyOpcodes.PUSH: 24>: <ducky.cpu.instructions.PUSH object>, <DuckyOpcodes.POP: 25>: <ducky.cpu.instructions.POP object>, <DuckyOpcodes.INC: 26>: <ducky.cpu.instructions.INC object>, <DuckyOpcodes.DEC: 27>: <ducky.cpu.instructions.DEC object>, <DuckyOpcodes.ADD: 28>: <ducky.cpu.instructions.ADD object>, <DuckyOpcodes.SUB: 29>: <ducky.cpu.instructions.SUB object>, <DuckyOpcodes.MUL: 30>: <ducky.cpu.instructions.MUL object>, <DuckyOpcodes.DIV: 31>: <ducky.cpu.instructions.DIV object>, <DuckyOpcodes.UDIV: 32>: <ducky.cpu.instructions.UDIV object>, <DuckyOpcodes.MOD: 33>: <ducky.cpu.instructions.MOD object>, <DuckyOpcodes.AND: 34>: <ducky.cpu.instructions.AND object>, <DuckyOpcodes.OR: 35>: <ducky.cpu.instructions.OR object>, <DuckyOpcodes.XOR: 36>: <ducky.cpu.instructions.XOR object>, <DuckyOpcodes.NOT: 37>: <ducky.cpu.instructions.NOT object>, <DuckyOpcodes.SHL: 38>: <ducky.cpu.instructions.SHL object>, <DuckyOpcodes.SHR: 39>: <ducky.cpu.instructions.SHR object>, <DuckyOpcodes.SHRS: 40>: <ducky.cpu.instructions.SHRS object>, <DuckyOpcodes.J: 46>: <ducky.cpu.instructions.J object>, <DuckyOpcodes.CMP: 47>: <ducky.cpu.instructions.CMP object>, <DuckyOpcodes.CMPU: 48>: <ducky.cpu.instructions.CMPU object>, <DuckyOpcodes.SET: 49>: <ducky.cpu.instructions.SETLE object>, <DuckyOpcodes.BRANCH: 50>: <ducky.cpu.instructions.BLE object>, <DuckyOpcodes.SELECT: 51>: <ducky.cpu.instructions.SELLE object>, <DuckyOpcodes.CTR: 60>: <ducky.cpu.instructions.CTR object>, <DuckyOpcodes.CTW: 61>: <ducky.cpu.instructions.CTW object>, <DuckyOpcodes.FPTC: 62>: <ducky.cpu.instructions.FPTC object>, <DuckyOpcodes.SIS: 63>: <ducky.cpu.instructions.SIS object>}¶
-
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.SHL: 38>: <class 'ducky.cpu.instructions.EncodingR'>, <DuckyOpcodes.SHR: 39>: <class 'ducky.cpu.instructions.EncodingR'>, <DuckyOpcodes.SHRS: 40>: <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.EncodingS'>, <DuckyOpcodes.BRANCH: 50>: <class 'ducky.cpu.instructions.EncodingC'>, <DuckyOpcodes.SELECT: 51>: <class 'ducky.cpu.instructions.EncodingS'>, <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
= 28¶
-
AND
= 34¶
-
BRANCH
= 50¶
-
CALL
= 15¶
-
CAS
= 7¶
-
CLI
= 17¶
-
CMP
= 47¶
-
CMPU
= 48¶
-
CTR
= 60¶
-
CTW
= 61¶
-
DEC
= 27¶
-
DIV
= 31¶
-
FPTC
= 62¶
-
HLT
= 20¶
-
IDLE
= 21¶
-
INC
= 26¶
-
INT
= 13¶
-
IPI
= 23¶
-
J
= 46¶
-
LA
= 8¶
-
LB
= 3¶
-
LI
= 9¶
-
LIU
= 10¶
-
LPM
= 22¶
-
LS
= 2¶
-
LW
= 1¶
-
MOD
= 33¶
-
MOV
= 11¶
-
MUL
= 30¶
-
NOP
= 0¶
-
NOT
= 37¶
-
OR
= 35¶
-
POP
= 25¶
-
PUSH
= 24¶
-
RET
= 16¶
-
RETINT
= 14¶
-
RST
= 19¶
-
SELECT
= 51¶
-
SET
= 49¶
-
SHL
= 38¶
-
SHR
= 39¶
-
SHRS
= 40¶
-
SIS
= 63¶
-
STB
= 6¶
-
STI
= 18¶
-
STS
= 5¶
-
STW
= 4¶
-
SUB
= 29¶
-
SWP
= 12¶
-
UDIV
= 32¶
-
XOR
= 36¶
-
_member_map_
= OrderedDict([('NOP', <DuckyOpcodes.NOP: 0>), ('LW', <DuckyOpcodes.LW: 1>), ('LS', <DuckyOpcodes.LS: 2>), ('LB', <DuckyOpcodes.LB: 3>), ('STW', <DuckyOpcodes.STW: 4>), ('STS', <DuckyOpcodes.STS: 5>), ('STB', <DuckyOpcodes.STB: 6>), ('CAS', <DuckyOpcodes.CAS: 7>), ('LA', <DuckyOpcodes.LA: 8>), ('LI', <DuckyOpcodes.LI: 9>), ('LIU', <DuckyOpcodes.LIU: 10>), ('MOV', <DuckyOpcodes.MOV: 11>), ('SWP', <DuckyOpcodes.SWP: 12>), ('INT', <DuckyOpcodes.INT: 13>), ('RETINT', <DuckyOpcodes.RETINT: 14>), ('CALL', <DuckyOpcodes.CALL: 15>), ('RET', <DuckyOpcodes.RET: 16>), ('CLI', <DuckyOpcodes.CLI: 17>), ('STI', <DuckyOpcodes.STI: 18>), ('RST', <DuckyOpcodes.RST: 19>), ('HLT', <DuckyOpcodes.HLT: 20>), ('IDLE', <DuckyOpcodes.IDLE: 21>), ('LPM', <DuckyOpcodes.LPM: 22>), ('IPI', <DuckyOpcodes.IPI: 23>), ('PUSH', <DuckyOpcodes.PUSH: 24>), ('POP', <DuckyOpcodes.POP: 25>), ('INC', <DuckyOpcodes.INC: 26>), ('DEC', <DuckyOpcodes.DEC: 27>), ('ADD', <DuckyOpcodes.ADD: 28>), ('SUB', <DuckyOpcodes.SUB: 29>), ('MUL', <DuckyOpcodes.MUL: 30>), ('DIV', <DuckyOpcodes.DIV: 31>), ('UDIV', <DuckyOpcodes.UDIV: 32>), ('MOD', <DuckyOpcodes.MOD: 33>), ('AND', <DuckyOpcodes.AND: 34>), ('OR', <DuckyOpcodes.OR: 35>), ('XOR', <DuckyOpcodes.XOR: 36>), ('NOT', <DuckyOpcodes.NOT: 37>), ('SHL', <DuckyOpcodes.SHL: 38>), ('SHR', <DuckyOpcodes.SHR: 39>), ('SHRS', <DuckyOpcodes.SHRS: 40>), ('J', <DuckyOpcodes.J: 46>), ('CMP', <DuckyOpcodes.CMP: 47>), ('CMPU', <DuckyOpcodes.CMPU: 48>), ('SET', <DuckyOpcodes.SET: 49>), ('BRANCH', <DuckyOpcodes.BRANCH: 50>), ('SELECT', <DuckyOpcodes.SELECT: 51>), ('CTR', <DuckyOpcodes.CTR: 60>), ('CTW', <DuckyOpcodes.CTW: 61>), ('FPTC', <DuckyOpcodes.FPTC: 62>), ('SIS', <DuckyOpcodes.SIS: 63>)])¶
-
_member_names_
= ['NOP', 'LW', 'LS', 'LB', 'STW', 'STS', 'STB', 'CAS', 'LA', 'LI', 'LIU', 'MOV', 'SWP', 'INT', 'RETINT', 'CALL', 'RET', 'CLI', 'STI', 'RST', 'HLT', 'IDLE', 'LPM', 'IPI', 'PUSH', 'POP', 'INC', 'DEC', 'ADD', 'SUB', 'MUL', 'DIV', 'UDIV', 'MOD', 'AND', 'OR', 'XOR', 'NOT', 'SHL', 'SHR', 'SHRS', 'J', 'CMP', 'CMPU', 'SET', 'BRANCH', 'SELECT', 'CTR', 'CTW', 'FPTC', 'SIS']¶
-
_member_type_
¶ alias of
int
-
_value2member_map_
= {0: <DuckyOpcodes.NOP: 0>, 1: <DuckyOpcodes.LW: 1>, 2: <DuckyOpcodes.LS: 2>, 3: <DuckyOpcodes.LB: 3>, 4: <DuckyOpcodes.STW: 4>, 5: <DuckyOpcodes.STS: 5>, 6: <DuckyOpcodes.STB: 6>, 7: <DuckyOpcodes.CAS: 7>, 8: <DuckyOpcodes.LA: 8>, 9: <DuckyOpcodes.LI: 9>, 10: <DuckyOpcodes.LIU: 10>, 11: <DuckyOpcodes.MOV: 11>, 12: <DuckyOpcodes.SWP: 12>, 13: <DuckyOpcodes.INT: 13>, 14: <DuckyOpcodes.RETINT: 14>, 15: <DuckyOpcodes.CALL: 15>, 16: <DuckyOpcodes.RET: 16>, 17: <DuckyOpcodes.CLI: 17>, 18: <DuckyOpcodes.STI: 18>, 19: <DuckyOpcodes.RST: 19>, 20: <DuckyOpcodes.HLT: 20>, 21: <DuckyOpcodes.IDLE: 21>, 22: <DuckyOpcodes.LPM: 22>, 23: <DuckyOpcodes.IPI: 23>, 24: <DuckyOpcodes.PUSH: 24>, 25: <DuckyOpcodes.POP: 25>, 26: <DuckyOpcodes.INC: 26>, 27: <DuckyOpcodes.DEC: 27>, 28: <DuckyOpcodes.ADD: 28>, 29: <DuckyOpcodes.SUB: 29>, 30: <DuckyOpcodes.MUL: 30>, 31: <DuckyOpcodes.DIV: 31>, 32: <DuckyOpcodes.UDIV: 32>, 33: <DuckyOpcodes.MOD: 33>, 34: <DuckyOpcodes.AND: 34>, 35: <DuckyOpcodes.OR: 35>, 36: <DuckyOpcodes.XOR: 36>, 37: <DuckyOpcodes.NOT: 37>, 38: <DuckyOpcodes.SHL: 38>, 39: <DuckyOpcodes.SHR: 39>, 40: <DuckyOpcodes.SHRS: 40>, 46: <DuckyOpcodes.J: 46>, 47: <DuckyOpcodes.CMP: 47>, 48: <DuckyOpcodes.CMPU: 48>, 49: <DuckyOpcodes.SET: 49>, 50: <DuckyOpcodes.BRANCH: 50>, 51: <DuckyOpcodes.SELECT: 51>, 60: <DuckyOpcodes.CTR: 60>, 61: <DuckyOpcodes.CTW: 61>, 62: <DuckyOpcodes.FPTC: 62>, 63: <DuckyOpcodes.SIS: 63>}¶
-
-
class
ducky.cpu.instructions.
EncodingA
[source]¶ Bases:
_ctypes.Structure
-
_fields_
= [('opcode', <class 'ctypes.c_uint'>, 6), ('reg1', <class 'ctypes.c_uint'>, 5), ('reg2', <class 'ctypes.c_uint'>, 5), ('reg3', <class 'ctypes.c_uint'>, 5)]¶
-
_pack_
= 0¶
-
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
-
_fields_
= [('opcode', <class 'ctypes.c_uint'>, 6), ('reg', <class 'ctypes.c_uint'>, 5), ('flag', <class 'ctypes.c_uint'>, 3), ('value', <class 'ctypes.c_uint'>, 1), ('immediate_flag', <class 'ctypes.c_uint'>, 1), ('immediate', <class 'ctypes.c_uint'>, 16)]¶
-
_pack_
= 0¶
-
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.
EncodingContext
(logger)[source]¶ Bases:
ducky.util.LoggingCapable
,object
-
class
ducky.cpu.instructions.
EncodingI
[source]¶ Bases:
_ctypes.Structure
-
_fields_
= [('opcode', <class 'ctypes.c_uint'>, 6), ('reg', <class 'ctypes.c_uint'>, 5), ('immediate_flag', <class 'ctypes.c_uint'>, 1), ('immediate', <class 'ctypes.c_uint'>, 20)]¶
-
_pack_
= 0¶
-
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
-
_fields_
= [('opcode', <class 'ctypes.c_uint'>, 6), ('reg1', <class 'ctypes.c_uint'>, 5), ('reg2', <class 'ctypes.c_uint'>, 5), ('immediate_flag', <class 'ctypes.c_uint'>, 1), ('immediate', <class 'ctypes.c_uint'>, 15)]¶
-
_pack_
= 0¶
-
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.
EncodingS
[source]¶ Bases:
_ctypes.Structure
-
_fields_
= [('opcode', <class 'ctypes.c_uint'>, 6), ('reg1', <class 'ctypes.c_uint'>, 5), ('reg2', <class 'ctypes.c_uint'>, 5), ('flag', <class 'ctypes.c_uint'>, 3), ('value', <class 'ctypes.c_uint'>, 1), ('immediate_flag', <class 'ctypes.c_uint'>, 1), ('immediate', <class 'ctypes.c_uint'>, 11)]¶
-
_pack_
= 0¶
-
flag
¶ Structure/Union member
-
immediate
¶ Structure/Union member
-
immediate_flag
¶ Structure/Union member
-
opcode
¶ Structure/Union member
-
reg1
¶ Structure/Union member
-
reg2
¶ Structure/Union member
-
value
¶ Structure/Union member
-
-
class
ducky.cpu.instructions.
FPTC
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor
-
mnemonic
= 'fptc'¶
-
opcode
= 62¶
-
operands
= []¶
-
-
class
ducky.cpu.instructions.
HLT
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor_RI
-
mnemonic
= 'hlt'¶
-
opcode
= 20¶
-
operands
= ['ri']¶
-
-
class
ducky.cpu.instructions.
IDLE
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor
-
mnemonic
= 'idle'¶
-
opcode
= 21¶
-
operands
= []¶
-
-
class
ducky.cpu.instructions.
INC
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor_R
-
mnemonic
= 'inc'¶
-
opcode
= 26¶
-
operands
= ['r']¶
-
-
class
ducky.cpu.instructions.
INT
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor_RI
-
mnemonic
= 'int'¶
-
opcode
= 13¶
-
operands
= ['ri']¶
-
-
class
ducky.cpu.instructions.
IPI
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor_R_RI
-
mnemonic
= 'ipi'¶
-
opcode
= 23¶
-
operands
= ['r', 'ri']¶
-
-
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
= 46¶
-
operands
= ['ri']¶
-
-
class
ducky.cpu.instructions.
LA
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._LOAD_IMM
-
mnemonic
= 'la'¶
-
opcode
= 8¶
-
operands
= ['r', 'i']¶
-
relative_address
= True¶
-
-
class
ducky.cpu.instructions.
LB
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._LOAD
-
mnemonic
= 'lb'¶
-
opcode
= 3¶
-
operands
= ['r', 'a']¶
-
-
class
ducky.cpu.instructions.
LI
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._LOAD_IMM
-
mnemonic
= 'li'¶
-
opcode
= 9¶
-
operands
= ['r', 'i']¶
-
-
class
ducky.cpu.instructions.
LIU
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._LOAD_IMM
-
mnemonic
= 'liu'¶
-
opcode
= 10¶
-
operands
= ['r', 'i']¶
-
-
class
ducky.cpu.instructions.
LPM
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor
-
mnemonic
= 'lpm'¶
-
opcode
= 22¶
-
operands
= []¶
-
-
class
ducky.cpu.instructions.
LS
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._LOAD
-
mnemonic
= 'ls'¶
-
opcode
= 2¶
-
operands
= ['r', 'a']¶
-
-
class
ducky.cpu.instructions.
LW
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._LOAD
-
mnemonic
= 'lw'¶
-
opcode
= 1¶
-
operands
= ['r', 'a']¶
-
-
class
ducky.cpu.instructions.
MOD
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BINOP
-
mnemonic
= 'mod'¶
-
opcode
= 33¶
-
operands
= ['r', 'ri']¶
-
-
class
ducky.cpu.instructions.
MOV
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor_R_R
-
mnemonic
= 'mov'¶
-
opcode
= 11¶
-
operands
= ['r', 'r']¶
-
-
class
ducky.cpu.instructions.
MUL
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BINOP
-
mnemonic
= 'mul'¶
-
opcode
= 30¶
-
operands
= ['r', 'ri']¶
-
-
class
ducky.cpu.instructions.
NOP
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor
-
mnemonic
= 'nop'¶
-
opcode
= 0¶
-
operands
= []¶
-
-
class
ducky.cpu.instructions.
NOT
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor_R
-
mnemonic
= 'not'¶
-
opcode
= 37¶
-
operands
= ['r']¶
-
-
class
ducky.cpu.instructions.
OR
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BITOP
-
mnemonic
= 'or'¶
-
opcode
= 35¶
-
operands
= ['r', 'ri']¶
-
-
class
ducky.cpu.instructions.
POP
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor_R
-
mnemonic
= 'pop'¶
-
opcode
= 25¶
-
operands
= ['r']¶
-
-
class
ducky.cpu.instructions.
PUSH
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor_RI
-
mnemonic
= 'push'¶
-
opcode
= 24¶
-
operands
= ['ri']¶
-
-
class
ducky.cpu.instructions.
RET
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor
-
mnemonic
= 'ret'¶
-
opcode
= 16¶
-
operands
= []¶
-
-
class
ducky.cpu.instructions.
RETINT
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor
-
mnemonic
= 'retint'¶
-
opcode
= 14¶
-
operands
= []¶
-
-
class
ducky.cpu.instructions.
RST
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor
-
mnemonic
= 'rst'¶
-
opcode
= 19¶
-
operands
= []¶
-
-
class
ducky.cpu.instructions.
SELE
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._SELECT
-
mnemonic
= 'sele'¶
-
operands
= ['r', 'ri']¶
-
-
class
ducky.cpu.instructions.
SELG
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._SELECT
-
mnemonic
= 'selg'¶
-
operands
= ['r', 'ri']¶
-
-
class
ducky.cpu.instructions.
SELGE
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._SELECT
-
mnemonic
= 'selge'¶
-
operands
= ['r', 'ri']¶
-
-
class
ducky.cpu.instructions.
SELL
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._SELECT
-
mnemonic
= 'sell'¶
-
operands
= ['r', 'ri']¶
-
-
class
ducky.cpu.instructions.
SELLE
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._SELECT
-
mnemonic
= 'selle'¶
-
operands
= ['r', 'ri']¶
-
-
class
ducky.cpu.instructions.
SELNE
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._SELECT
-
mnemonic
= 'selne'¶
-
operands
= ['r', 'ri']¶
-
-
class
ducky.cpu.instructions.
SELNO
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._SELECT
-
mnemonic
= 'selno'¶
-
operands
= ['r', 'ri']¶
-
-
class
ducky.cpu.instructions.
SELNS
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._SELECT
-
mnemonic
= 'selns'¶
-
operands
= ['r', 'ri']¶
-
-
class
ducky.cpu.instructions.
SELNZ
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._SELECT
-
mnemonic
= 'selnz'¶
-
operands
= ['r', 'ri']¶
-
-
class
ducky.cpu.instructions.
SELO
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._SELECT
-
mnemonic
= 'selo'¶
-
operands
= ['r', 'ri']¶
-
-
class
ducky.cpu.instructions.
SELS
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._SELECT
-
mnemonic
= 'sels'¶
-
operands
= ['r', 'ri']¶
-
-
class
ducky.cpu.instructions.
SELZ
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._SELECT
-
mnemonic
= 'selz'¶
-
operands
= ['r', 'ri']¶
-
-
class
ducky.cpu.instructions.
SETE
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._SET
-
mnemonic
= 'sete'¶
-
operands
= ['r']¶
-
-
class
ducky.cpu.instructions.
SETG
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._SET
-
mnemonic
= 'setg'¶
-
operands
= ['r']¶
-
-
class
ducky.cpu.instructions.
SETGE
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._SET
-
mnemonic
= 'setge'¶
-
operands
= ['r']¶
-
-
class
ducky.cpu.instructions.
SETL
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._SET
-
mnemonic
= 'setl'¶
-
operands
= ['r']¶
-
-
class
ducky.cpu.instructions.
SETLE
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._SET
-
mnemonic
= 'setle'¶
-
operands
= ['r']¶
-
-
class
ducky.cpu.instructions.
SETNE
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._SET
-
mnemonic
= 'setne'¶
-
operands
= ['r']¶
-
-
class
ducky.cpu.instructions.
SETNO
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._SET
-
mnemonic
= 'setno'¶
-
operands
= ['r']¶
-
-
class
ducky.cpu.instructions.
SETNS
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._SET
-
mnemonic
= 'setns'¶
-
operands
= ['r']¶
-
-
class
ducky.cpu.instructions.
SETNZ
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._SET
-
mnemonic
= 'setnz'¶
-
operands
= ['r']¶
-
-
class
ducky.cpu.instructions.
SETO
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._SET
-
mnemonic
= 'seto'¶
-
operands
= ['r']¶
-
-
class
ducky.cpu.instructions.
SETS
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._SET
-
mnemonic
= 'sets'¶
-
operands
= ['r']¶
-
-
class
ducky.cpu.instructions.
SETZ
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._SET
-
mnemonic
= 'setz'¶
-
operands
= ['r']¶
-
-
class
ducky.cpu.instructions.
SHL
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BITOP
-
mnemonic
= 'shiftl'¶
-
opcode
= 38¶
-
operands
= ['r', 'ri']¶
-
-
class
ducky.cpu.instructions.
SHR
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BITOP
-
mnemonic
= 'shiftr'¶
-
opcode
= 39¶
-
operands
= ['r', 'ri']¶
-
-
class
ducky.cpu.instructions.
SHRS
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BITOP
-
mnemonic
= 'shiftrs'¶
-
opcode
= 40¶
-
operands
= ['r', 'ri']¶
-
-
class
ducky.cpu.instructions.
SIS
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor_RI
-
mnemonic
= 'sis'¶
-
opcode
= 63¶
-
operands
= ['ri']¶
-
-
class
ducky.cpu.instructions.
STB
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._STORE
-
mnemonic
= 'stb'¶
-
opcode
= 6¶
-
operands
= ['a', 'r']¶
-
-
class
ducky.cpu.instructions.
STI
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor
-
mnemonic
= 'sti'¶
-
opcode
= 18¶
-
operands
= []¶
-
-
class
ducky.cpu.instructions.
STS
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._STORE
-
mnemonic
= 'sts'¶
-
opcode
= 5¶
-
operands
= ['a', 'r']¶
-
-
class
ducky.cpu.instructions.
STW
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._STORE
-
mnemonic
= 'stw'¶
-
opcode
= 4¶
-
operands
= ['a', 'r']¶
-
-
class
ducky.cpu.instructions.
SUB
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BINOP
-
mnemonic
= 'sub'¶
-
opcode
= 29¶
-
operands
= ['r', 'ri']¶
-
-
class
ducky.cpu.instructions.
SWP
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor_R_R
-
mnemonic
= 'swp'¶
-
opcode
= 12¶
-
operands
= ['r', 'r']¶
-
-
class
ducky.cpu.instructions.
UDIV
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BINOP
-
mnemonic
= 'udiv'¶
-
opcode
= 32¶
-
operands
= ['r', 'ri']¶
-
-
class
ducky.cpu.instructions.
XOR
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._BITOP
-
mnemonic
= 'xor'¶
-
opcode
= 36¶
-
operands
= ['r', 'ri']¶
-
-
class
ducky.cpu.instructions.
_BRANCH
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._COND
-
inst_aligned
= True¶
-
opcode
= 50¶
-
operands
= 'ri'¶
-
relative_address
= True¶
-
-
class
ducky.cpu.instructions.
_CMP
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor_R_RI
-
static
evaluate
(core, x, y, signed=True)[source]¶ Compare two numbers, and update relevant flags. Signed comparison is used unless
signed
isFalse
. All arithmetic flags are set to zero before the relevant ones are set.O
flag is reset like the others, therefore caller has to take care of it’s setting if it’s required to set it.Parameters: - x (u32) – left hand number
- y (u32) – right hand number
- signed (bool) – use signed, defaults to
True
-
static
-
class
ducky.cpu.instructions.
_COND
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor
-
FLAGS
= ['arith_equal', 'arith_zero', 'arith_overflow', 'arith_sign', 'l', 'g']¶
-
GFLAGS
= [0, 1, 2, 3]¶
-
MNEMONICS
= ['e', 'z', 'o', 's', 'g', 'l']¶
-
-
class
ducky.cpu.instructions.
_JUMP
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor
-
inst_aligned
= True¶
-
operands
= 'ri'¶
-
relative_address
= True¶
-
-
class
ducky.cpu.instructions.
_LOAD
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor
-
operands
= 'r,a'¶
-
-
class
ducky.cpu.instructions.
_SELECT
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor
-
opcode
= 51¶
-
operands
= 'r,ri'¶
-
-
class
ducky.cpu.instructions.
_SET
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions._COND
-
opcode
= 49¶
-
operands
= 'r'¶
-
-
class
ducky.cpu.instructions.
_STORE
(instruction_set)[source]¶ Bases:
ducky.cpu.instructions.Descriptor
-
operands
= 'a,r'¶
-
-
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
= 33¶
-
FP
= 30¶
-
IP
= 32¶
-
R00
= 0¶
-
R01
= 1¶
-
R02
= 2¶
-
R03
= 3¶
-
R04
= 4¶
-
R05
= 5¶
-
R06
= 6¶
-
R07
= 7¶
-
R08
= 8¶
-
R09
= 9¶
-
R10
= 10¶
-
R11
= 11¶
-
R12
= 12¶
-
R13
= 13¶
-
R14
= 14¶
-
R15
= 15¶
-
R16
= 16¶
-
R17
= 17¶
-
R18
= 18¶
-
R19
= 19¶
-
R20
= 20¶
-
R21
= 21¶
-
R22
= 22¶
-
R23
= 23¶
-
R24
= 24¶
-
R25
= 25¶
-
R26
= 26¶
-
R27
= 27¶
-
R28
= 28¶
-
R29
= 29¶
-
REGISTER_COUNT
= 34¶
-
REGISTER_SPECIAL
= 30¶
-
SP
= 31¶
-
_member_map_
= OrderedDict([('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>), ('FP', <Registers.FP: 30>), ('REGISTER_SPECIAL', <Registers.FP: 30>), ('SP', <Registers.SP: 31>), ('IP', <Registers.IP: 32>), ('CNT', <Registers.CNT: 33>), ('REGISTER_COUNT', <Registers.REGISTER_COUNT: 34>)])¶
-
_member_names_
= ['R00', 'R01', 'R02', 'R03', 'R04', 'R05', 'R06', 'R07', 'R08', 'R09', 'R10', 'R11', 'R12', 'R13', 'R14', 'R15', 'R16', 'R17', 'R18', 'R19', 'R20', 'R21', 'R22', 'R23', 'R24', 'R25', 'R26', 'R27', 'R28', 'R29', 'FP', 'SP', 'IP', 'CNT', 'REGISTER_COUNT']¶
-
_member_type_
¶ alias of
int
-
_value2member_map_
= {0: <Registers.R00: 0>, 1: <Registers.R01: 1>, 2: <Registers.R02: 2>, 3: <Registers.R03: 3>, 4: <Registers.R04: 4>, 5: <Registers.R05: 5>, 6: <Registers.R06: 6>, 7: <Registers.R07: 7>, 8: <Registers.R08: 8>, 9: <Registers.R09: 9>, 10: <Registers.R10: 10>, 11: <Registers.R11: 11>, 12: <Registers.R12: 12>, 13: <Registers.R13: 13>, 14: <Registers.R14: 14>, 15: <Registers.R15: 15>, 16: <Registers.R16: 16>, 17: <Registers.R17: 17>, 18: <Registers.R18: 18>, 19: <Registers.R19: 19>, 20: <Registers.R20: 20>, 21: <Registers.R21: 21>, 22: <Registers.R22: 22>, 23: <Registers.R23: 23>, 24: <Registers.R24: 24>, 25: <Registers.R25: 25>, 26: <Registers.R26: 26>, 27: <Registers.R27: 27>, 28: <Registers.R28: 28>, 29: <Registers.R29: 29>, 30: <Registers.FP: 30>, 31: <Registers.SP: 31>, 32: <Registers.IP: 32>, 33: <Registers.CNT: 33>, 34: <Registers.REGISTER_COUNT: 34>}¶
-
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.
-
_CPUCore__get_flags
()¶
-
_CPUCore__set_flags
(flags)¶
-
_enter_exception
(index, *args)[source]¶ Prepare CPU for handling exception routine. CPU core loads new
IP
andSP
from proper entry of EVT. OldSP
andFLAGS
are saved on the exception stack, and new call frame is created. Privileged mode flag is set, hardware interrupt flag is cleared.Then, if exception provides its routine with some arguments, these arguments are pushed on the stack.
Exception stack layout then looks like this (original stack is left untouched):
+---------+ <= EVT SP | SP | +---------+ | FLAGS | +---------+ | IP | +---------+ | FP | +---------+ <= FP | arg1 | +---------+ | ... | +---------+ | argN | +---------+ <= SP | ... | +---------+
Parameters: - index (int) – exception ID - EVT index.
- args (u32_t) – if present, these values will be pushed onto the stack.
-
_exit_exception
()[source]¶ Restore CPU state after running an exception routine. Call frame is destroyed, registers are restored. Clearing routine arguments is responsibility of the routine.
-
_handle_exception
(exc, index, *args)[source]¶ This method provides CPU exception classes with a simple recipe on how to deal with the exception:
- tell processor to start exception dance,
- if the exception is raised again, tell processor to plan double fault routine,
- and if yet another exception is raised, halt the core.
-
_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
-
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: ducky.errors.PrivilegedInstructionError – if the core is not in privileged mode
-
create_frame
()[source]¶ Creates new call stack frame, by performing the following operations:
- push
IP
- push
FP
- set
FP
toSP
(i.e.SP
before this method + 2 pushes)
Stack layout then looks like this:
+---------+ | IPx | +---------+ | FPx | +---------+ <= FPy | ... | +---------+ <= original SP | IPy | +---------+ | FPy | +---------+ <= SP, FP | ... | +---------+
FP
then points to the newly created frame, to the savedFP
in particular, and this savedFP
points to its predecesor, thus forming a chain.- push
-
destroy_frame
()[source]¶ Destroys current call stack frame by popping values from the stack, reversing the list of operations performed by
ducky.cpu.CPUCore.create_frame()
:- pop
FP
- pop
IP
After this,
FP
points to the frame from which the instruction that created the currently destroyed frame was executed, and restoredIP
points to the next instruction.Raises: InvalidFrameError – if frame checking is enabled, current SP
is compared with savedFP
to see, if the stack was clean before leaving the frame. This error indicated there is some value left on stack whenret
orretint
were executed. Usually, this signals missingpop
to complement one of previous ``push``es.- pop
-
flags
¶
-
instruction_set
¶
-
irq
(index)[source]¶ This is a wrapper for _enter_exception, for device drivers to call when hardware interrupt arrives.
Parameters: index (int) – exception ID - EVT index
-
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
-
class
ducky.cpu.
CPUState
(*fields)[source]¶ Bases:
ducky.snapshot.SnapshotNode
-
class
ducky.cpu.
CoreFlags
[source]¶ Bases:
ducky.util.Flags
-
_flags
= ['privileged', 'hwint_allowed', 'equal', 'zero', 'overflow', 'sign']¶
-
_labels
= 'PHEZOS'¶
-
-
ducky.cpu.
DEFAULT_CORE_INST_CACHE_SIZE
= 256¶ Default size of core instruction cache, in instructions.
-
ducky.cpu.
DEFAULT_EVT_ADDRESS
= 0¶ Default EVT address
-
ducky.cpu.
DEFAULT_PT_ADDRESS
= 65536¶ Default PT address
-
class
ducky.cpu.
InstructionCache_Base
(mmu, *args, **kwargs)[source]¶ Bases:
ducky.util.LoggingCapable
,dict
Simple instruction cache class, based on a dictionary, with a limited size.
Parameters: core (ducky.cpu.CPUCore) – CPU core that owns this cache.
-
class
ducky.cpu.
InstructionCache_Full
(mmu, *args, **kwargs)[source]¶ Bases:
ducky.util.LoggingCapable
,list
Simple instruction cache class, based on a list, with unlimited size.
Parameters: core (ducky.cpu.CPUCore) – CPU core that owns this cache.
-
class
ducky.cpu.
InterruptVector
(ip=0, sp=0)[source]¶ Bases:
object
Interrupt vector table entry.
-
SIZE
= 8¶
-
-
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.
- memory.force-aligned-access (bool) – if set, MMU will disallow unaligned
reads and writes.
False
by default. - cpu.pt-address (int) – base address of page table.
ducky.cpu.DEFAULT_PT_ADDRESS
by default. - cpu.pt-enabled (bool) – if set, CPU core will start with page table
enabled.
False
by default.
-
_check_access
(access, addr, align=None)[source]¶ Check attempted access against several criteria:
- PT is enabled - disabled PT implies different set of read/write methods that don’t use this method to check access
- access alignment if correct alignment is required
- privileged access implies granted access
- corresponding PTE settings
Parameters: - access –
read
,write
orexecute
. - addr (int) – memory address.
- align (int) – if set, operation is expected to be aligned to this boundary.
Raises: - ducky.errors.UnalignedAccessError – when unaligned access is not allowed, but requested.
- ducky.errors.MemoryAccessError – when access is denied.
-
_fetch_instr
(addr)[source]¶ Read instruction from memory. This method is responsible for the real job of fetching instructions and filling the cache.
Parameters: addr (u24) – absolute address to read from Returns: instruction Return type: InstBinaryFormat_Master
-
_fetch_instr_jit
(addr)[source]¶ Read instruction from memory. This method is responsible for the real job of fetching instructions and filling the cache.
Parameters: addr (u24) – absolute address to read from Returns: instruction Return type: InstBinaryFormat_Master
-
_get_pte
(addr)[source]¶ Find out PTE for particular physical address. If PTE is not in internal PTE cache, it is fetched from PTE table.
Parameters: addr (int) – memory address.
-
_set_access_methods
()[source]¶ Set parent core’s memory-access methods to proper shortcuts. Methods named
MEM_{IN,OUT}{8,16,32}
will be set to corresponding MMU methods.
-
pt_enabled
¶
-
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.
DebuggingSet
(core)[source]¶ Bases:
object
-
_DebuggingSet__check_chain
(stage, chain, clean_triggered=False, *args, **kwargs)¶
-
-
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.
-
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, mmio_address=None, irq=None)[source]¶ Bases:
ducky.devices.DeviceBackend
-
class
ducky.devices.keyboard.
ControlMessages
[source]¶ Bases:
enum.IntEnum
-
CONTROL_MESSAGE_FIRST
= 1024¶
-
HALT
= 1025¶
-
_member_map_
= OrderedDict([('CONTROL_MESSAGE_FIRST', <ControlMessages.CONTROL_MESSAGE_FIRST: 1024>), ('HALT', <ControlMessages.HALT: 1025>)])¶
-
_member_names_
= ['CONTROL_MESSAGE_FIRST', 'HALT']¶
-
_member_type_
¶ alias of
int
-
_value2member_map_
= {1024: <ControlMessages.CONTROL_MESSAGE_FIRST: 1024>, 1025: <ControlMessages.HALT: 1025>}¶
-
-
class
ducky.devices.keyboard.
Frontend
(machine, name)[source]¶ Bases:
ducky.devices.DeviceFrontend
-
class
ducky.devices.keyboard.
HDTEntry_Keyboard
(logger, config, section)[source]¶ Bases:
ducky.hdt.HDTEntry_Device
-
_fields_
= [('type', <class 'ctypes.c_ushort'>), ('length', <class 'ctypes.c_ushort'>), ('name_length', <class 'ctypes.c_ubyte'>), ('flags', <class 'ctypes.c_ubyte'>), ('name', <class 'ducky.hdt.c_ubyte_Array_10'>), ('ident', <class 'ducky.hdt.c_ubyte_Array_32'>), ('mmio_address', <class 'ctypes.c_uint'>)]¶
-
flags
¶ Structure/Union member
-
ident
¶ Structure/Union member
-
length
¶ Structure/Union member
-
mmio_address
¶ Structure/Union member
-
name
¶ Structure/Union member
-
name_length
¶ Structure/Union member
-
type
¶ Structure/Union member
-
-
class
ducky.devices.keyboard.
KeyboardMMIOMemoryPage
(device, *args, **kwargs)[source]¶ Bases:
ducky.devices.MMIOMemoryPage
-
class
ducky.devices.keyboard.
KeyboardPorts
[source]¶ Bases:
enum.IntEnum
-
DATA
= 1¶
-
LAST
= 1¶
-
STATUS
= 0¶
-
_member_map_
= OrderedDict([('STATUS', <KeyboardPorts.STATUS: 0>), ('DATA', <KeyboardPorts.DATA: 1>), ('LAST', <KeyboardPorts.DATA: 1>)])¶
-
_member_names_
= ['STATUS', 'DATA']¶
-
_member_type_
¶ alias of
int
-
_value2member_map_
= {0: <KeyboardPorts.STATUS: 0>, 1: <KeyboardPorts.DATA: 1>}¶
-
ducky.devices.rtc module¶
-
class
ducky.devices.rtc.
HDTEntry_RTC
(logger, config, section)[source]¶ Bases:
ducky.hdt.HDTEntry_Device
-
_fields_
= [('type', <class 'ctypes.c_ushort'>), ('length', <class 'ctypes.c_ushort'>), ('name_length', <class 'ctypes.c_ubyte'>), ('flags', <class 'ctypes.c_ubyte'>), ('name', <class 'ducky.hdt.c_ubyte_Array_10'>), ('ident', <class 'ducky.hdt.c_ubyte_Array_32'>), ('mmio_address', <class 'ctypes.c_uint'>)]¶
-
flags
¶ Structure/Union member
-
ident
¶ Structure/Union member
-
length
¶ Structure/Union member
-
mmio_address
¶ Structure/Union member
-
name
¶ Structure/Union member
-
name_length
¶ Structure/Union member
-
type
¶ Structure/Union member
-
-
class
ducky.devices.rtc.
RTC
(machine, name, frequency=None, mmio_address=None, irq=None, *args, **kwargs)[source]¶ Bases:
ducky.devices.Device
-
frequency
¶
-
-
class
ducky.devices.rtc.
RTCMMIOMemoryPage
(device, *args, **kwargs)[source]¶ Bases:
ducky.devices.MMIOMemoryPage
-
class
ducky.devices.rtc.
RTCPorts
[source]¶ Bases:
enum.IntEnum
-
DAY
= 5¶
-
FREQUENCY
= 0¶
-
HOUR
= 4¶
-
MINUTE
= 2¶
-
MONTH
= 6¶
-
SECOND
= 1¶
-
YEAR
= 6¶
-
_member_map_
= OrderedDict([('FREQUENCY', <RTCPorts.FREQUENCY: 0>), ('SECOND', <RTCPorts.SECOND: 1>), ('MINUTE', <RTCPorts.MINUTE: 2>), ('HOUR', <RTCPorts.HOUR: 4>), ('DAY', <RTCPorts.DAY: 5>), ('MONTH', <RTCPorts.MONTH: 6>), ('YEAR', <RTCPorts.MONTH: 6>)])¶
-
_member_names_
= ['FREQUENCY', 'SECOND', 'MINUTE', 'HOUR', 'DAY', 'MONTH']¶
-
_member_type_
¶ alias of
int
-
_value2member_map_
= {0: <RTCPorts.FREQUENCY: 0>, 1: <RTCPorts.SECOND: 1>, 2: <RTCPorts.MINUTE: 2>, 4: <RTCPorts.HOUR: 4>, 5: <RTCPorts.DAY: 5>, 6: <RTCPorts.MONTH: 6>}¶
-
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. 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.
Block IO subsystem transfers blocks between storages and VM,
-
ducky.devices.storage.
BIO_BUSY
= 16¶ Data transfer in progress.
-
ducky.devices.storage.
BIO_DMA
= 32¶ Request direct memory access - data will be transfered directly between storage and RAM..
-
ducky.devices.storage.
BIO_ERR
= 2¶ Error happened while performing the operation.
-
ducky.devices.storage.
BIO_RDY
= 1¶ Operation is completed, user can access data and/or request another operation
-
ducky.devices.storage.
BIO_READ
= 4¶ Request data read - transfer data from storage to memory.
-
ducky.devices.storage.
BIO_SRST
= 64¶ Reset BIO.
-
ducky.devices.storage.
BIO_USER
= 108¶ Flags that user can set - others are read-only.
-
ducky.devices.storage.
BIO_WRITE
= 8¶ Request data write - transfer data from memory to storage.
-
ducky.devices.storage.
BLOCK_SIZE
= 1024¶ Size of block, in bytes.
-
class
ducky.devices.storage.
BlockIO
(machine, name, mmio_address=None, irq=None, *args, **kwargs)[source]¶ Bases:
ducky.devices.Device
-
_flag_error
()[source]¶ Signals BIO request failed: BIO_ERR is set, and both BIO_RDY and BIO_BUSY are cleared.
-
_flag_finished
()[source]¶ Signals BIO is ready to accept new request: BIO_RDY is set, and BIO_BUSY is cleared.
If there was an request running, it is finished now. User can queue another request, or access data in case read by the last request.
-
-
class
ducky.devices.storage.
BlockIOMMIOMemoryPage
(device, *args, **kwargs)[source]¶ Bases:
ducky.devices.MMIOMemoryPage
-
class
ducky.devices.storage.
BlockIOPorts
[source]¶ Bases:
enum.IntEnum
MMIO ports, in form of offsets from a base MMIO address.
-
ADDR
= 16¶ Address of a memory buffer
-
BLOCK
= 8¶ Block ID
-
COUNT
= 12¶ Number of blocks
-
DATA
= 20¶ Data port, for non-DMA access
-
SID
= 4¶ ID of selected storage device
-
STATUS
= 0¶ Status port - query BIO status, and submit commands by setting flags
-
_member_map_
= OrderedDict([('STATUS', <BlockIOPorts.STATUS: 0>), ('SID', <BlockIOPorts.SID: 4>), ('BLOCK', <BlockIOPorts.BLOCK: 8>), ('COUNT', <BlockIOPorts.COUNT: 12>), ('ADDR', <BlockIOPorts.ADDR: 16>), ('DATA', <BlockIOPorts.DATA: 20>)])¶
-
_member_names_
= ['STATUS', 'SID', 'BLOCK', 'COUNT', 'ADDR', 'DATA']¶
-
_member_type_
¶ alias of
int
-
_value2member_map_
= {0: <BlockIOPorts.STATUS: 0>, 4: <BlockIOPorts.SID: 4>, 8: <BlockIOPorts.BLOCK: 8>, 12: <BlockIOPorts.COUNT: 12>, 16: <BlockIOPorts.ADDR: 16>, 20: <BlockIOPorts.DATA: 20>}¶
-
-
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, mmio_address=None, *args, **kwargs)[source]¶ Bases:
ducky.devices.DeviceBackend
-
class
ducky.devices.tty.
Frontend
(machine, name)[source]¶ Bases:
ducky.devices.DeviceFrontend
-
class
ducky.devices.tty.
HDTEntry_TTY
(logger, config, section)[source]¶ Bases:
ducky.hdt.HDTEntry_Device
-
_fields_
= [('type', <class 'ctypes.c_ushort'>), ('length', <class 'ctypes.c_ushort'>), ('name_length', <class 'ctypes.c_ubyte'>), ('flags', <class 'ctypes.c_ubyte'>), ('name', <class 'ducky.hdt.c_ubyte_Array_10'>), ('ident', <class 'ducky.hdt.c_ubyte_Array_32'>), ('mmio_address', <class 'ctypes.c_uint'>)]¶
-
flags
¶ Structure/Union member
-
ident
¶ Structure/Union member
-
length
¶ Structure/Union member
-
mmio_address
¶ Structure/Union member
-
name
¶ Structure/Union member
-
name_length
¶ Structure/Union member
-
type
¶ Structure/Union member
-
-
class
ducky.devices.tty.
TTYMMIOMemoryPage
(device, *args, **kwargs)[source]¶ Bases:
ducky.devices.MMIOMemoryPage
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
-
_fields_
= [('codepoint', <class 'ctypes.c_ushort'>, 7), ('unused', <class 'ctypes.c_ushort'>, 1), ('fg', <class 'ctypes.c_ushort'>, 4), ('bg', <class 'ctypes.c_ushort'>, 3), ('blink', <class 'ctypes.c_ushort'>, 1)]¶
-
_pack_
= 0¶
-
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_MMIO_ADDRESS
= 33024¶ Default MMIO address
-
ducky.devices.svga.
DEFAULT_MODES
= [(g, 320, 200, 1), (t, 80, 25, 2), (t, 80, 25, 1)]¶ Default list of available modes
-
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, memory_size=None, mmio_address=None, memory_address=None, memory_banks=None, modes=None, boot_mode=None, *args, **kwargs)[source]¶ Bases:
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.
- memory_size (int) – size of graphic memory.
- mmio_address (u32_t) – base oddress of MMIO ports.
- 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
= 33¶
-
DEPTH
= 35¶
-
GRAPHIC
= 32¶
-
MEMORY_BANK_ID
= 48¶
-
REFRESH
= 2¶
-
RESET
= 1¶
-
ROWS
= 34¶
-
_member_map_
= OrderedDict([('RESET', <SimpleVGACommands.RESET: 1>), ('REFRESH', <SimpleVGACommands.REFRESH: 2>), ('GRAPHIC', <SimpleVGACommands.GRAPHIC: 32>), ('COLS', <SimpleVGACommands.COLS: 33>), ('ROWS', <SimpleVGACommands.ROWS: 34>), ('DEPTH', <SimpleVGACommands.DEPTH: 35>), ('MEMORY_BANK_ID', <SimpleVGACommands.MEMORY_BANK_ID: 48>)])¶
-
_member_names_
= ['RESET', 'REFRESH', 'GRAPHIC', 'COLS', 'ROWS', 'DEPTH', 'MEMORY_BANK_ID']¶
-
_member_type_
¶ alias of
int
-
_value2member_map_
= {32: <SimpleVGACommands.GRAPHIC: 32>, 1: <SimpleVGACommands.RESET: 1>, 2: <SimpleVGACommands.REFRESH: 2>, 35: <SimpleVGACommands.DEPTH: 35>, 33: <SimpleVGACommands.COLS: 33>, 34: <SimpleVGACommands.ROWS: 34>, 48: <SimpleVGACommands.MEMORY_BANK_ID: 48>}¶
-
-
class
ducky.devices.svga.
SimpleVGAMMIOMemoryPage
(device, *args, **kwargs)[source]¶ Bases:
ducky.devices.MMIOMemoryPage
-
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.
-
class
ducky.devices.svga.
SimpleVGAPorts
[source]¶ Bases:
enum.IntEnum
-
CONTROL
= 0¶
-
DATA
= 2¶
-
_member_map_
= OrderedDict([('CONTROL', <SimpleVGAPorts.CONTROL: 0>), ('DATA', <SimpleVGAPorts.DATA: 2>)])¶
-
_member_names_
= ['CONTROL', 'DATA']¶
-
_member_type_
¶ alias of
int
-
_value2member_map_
= {0: <SimpleVGAPorts.CONTROL: 0>, 2: <SimpleVGAPorts.DATA: 2>}¶
-
Module contents¶
Emulating different virtual devices like keyboard, display, disks...
-
class
ducky.devices.
Device
(machine, klass, name)[source]¶ Bases:
ducky.interfaces.IMachineWorker
Base class for all devices. Serves more like an API description.
Parameters: - machine (ducky.machine.Machine) – VM this device belongs to.
- klass (str) – device family (input, output, snapshot, ...)
- name (str) – device name. Maps directly to a section of config file that hosts setup for this device.
-
static
create_from_config
(machine, config, section)[source]¶ Create new instance, configured exactly as requested by configuration file.
Parameters: - machine (ducky.machine.Machine) – VM this device belongs to.
- config (ducky.config.MachineConfig) – configuration file.
- section (str) – name of config section with this device’s setup.
-
static
create_hdt_entries
(logger, config, section)[source]¶ Create
HDT
entries for this device, based on configuration file.Parameters: - logger (logging.Logger) – logger to use for logging.
- config (ducky.config.MachineConfig) – configuration file.
- section (str) – name of config section with this device’s setup.
Return type: list
ofducky.hdt.HDTEntry
Returns: list of
HDT
entries. This list is then appended to entries of other devices.
-
class
ducky.devices.
DeviceBackend
(machine, klass, name)[source]¶ Bases:
ducky.devices.Device
Backend is a special component of a device, which is connected to internal queues, and processes events in the queue, originating from user via its frontend counterpart.
-
class
ducky.devices.
DeviceFrontend
(machine, klass, name)[source]¶ Bases:
ducky.devices.Device
Frontend is a special component of a device, that interfaces communication channels from user and internal queues.
-
set_backend
(device)[source]¶ Set backend counterpart.
Parameters: device (ducky.devices.DeviceFrontend) – backend part.
-
-
class
ducky.devices.
MMIOMemoryPage
(device, *args, **kwargs)[source]¶ Bases:
ducky.mm.VirtualMemoryPage
Memory page, suited for memory-mapped IO, supported by a device driver.
Parameters: device (ducky.devices.Device) – device instance, backing this memory page.
ducky.errors module¶
-
exception
ducky.errors.
AccessViolationError
(message=None)[source]¶ Bases:
ducky.errors.Error
Raised when an operation was requested without having adequate permission to do so.
message
attribute will provide better idea about the fault.
-
exception
ducky.errors.
AssemblerError
(location=None, message=None, line=None, info=None)[source]¶ Bases:
ducky.errors.Error
Base class for all assembler-related exceptions. Provides common properties, helping to locate related input in the source file.
Parameters: - location (ducky.cpu.assembly.SourceLocation) – if set, points to the location in the source file that was processed when the exception occured.
- message (str) – more detailed description.
- line (str) – input source line.
- info – additional details of the exception. This value is usually part
of the
message
, but is stored as well.
-
exception
ducky.errors.
AssemblyIllegalCharError
(c=None, **kwargs)[source]¶ Bases:
ducky.errors.AssemblerError
-
exception
ducky.errors.
AssemblyParseError
(token=None, **kwargs)[source]¶ Bases:
ducky.errors.AssemblerError
-
exception
ducky.errors.
BadLinkerScriptError
(script, exc, *args, **kwargs)[source]¶ Bases:
ducky.errors.LinkerError
-
exception
ducky.errors.
ConflictingNamesError
(**kwargs)[source]¶ Bases:
ducky.errors.AssemblerError
-
exception
ducky.errors.
CoprocessorError
(msg, *args, **kwargs)[source]¶ Bases:
ducky.errors.ExecutionException__SimpleESR
,ducky.errors.ExecutionException
Base class for coprocessor errors. Raised when coprocessors needs to signal its own exception, when none of alread yavailable exceptions would do.
-
EXCEPTION_INDEX
= 25¶
-
-
exception
ducky.errors.
DisassembleMismatchError
(**kwargs)[source]¶ Bases:
ducky.errors.AssemblerError
-
exception
ducky.errors.
DivideByZeroError
(*args, **kwargs)[source]¶ Bases:
ducky.errors.ExecutionException__SimpleESR
,ducky.errors.ExecutionException
Raised when divisor in a mathematical operation was equal to zero.
-
EXCEPTION_INDEX
= 18¶
-
-
exception
ducky.errors.
EncodingLargeValueError
(**kwargs)[source]¶ Bases:
ducky.errors.AssemblerError
-
exception
ducky.errors.
Error
(message=None)[source]¶ Bases:
exceptions.Exception
Base class for all Ducky exceptions.
Parameters: message (str) – optional description.
-
class
ducky.errors.
ExceptionList
[source]¶ Bases:
enum.IntEnum
List of exception IDs (
EVT
indices).-
COUNT
= 32¶
-
CoprocessorError
= 25¶
-
DivideByZero
= 18¶
-
DoubleFault
= 21¶
-
FIRST_HW
= 0¶
-
FIRST_SW
= 16¶
-
InvalidException
= 24¶
-
InvalidInstSet
= 17¶
-
InvalidOpcode
= 16¶
-
LAST_HW
= 15¶
-
LAST_SW
= 31¶
-
MemoryAccess
= 22¶
-
PrivilegedInstr
= 20¶
-
RegisterAccess
= 23¶
-
UnalignedAccess
= 19¶
-
_member_map_
= OrderedDict([('FIRST_HW', <ExceptionList.FIRST_HW: 0>), ('LAST_HW', <ExceptionList.LAST_HW: 15>), ('InvalidOpcode', <ExceptionList.InvalidOpcode: 16>), ('FIRST_SW', <ExceptionList.InvalidOpcode: 16>), ('InvalidInstSet', <ExceptionList.InvalidInstSet: 17>), ('DivideByZero', <ExceptionList.DivideByZero: 18>), ('UnalignedAccess', <ExceptionList.UnalignedAccess: 19>), ('PrivilegedInstr', <ExceptionList.PrivilegedInstr: 20>), ('DoubleFault', <ExceptionList.DoubleFault: 21>), ('MemoryAccess', <ExceptionList.MemoryAccess: 22>), ('RegisterAccess', <ExceptionList.RegisterAccess: 23>), ('InvalidException', <ExceptionList.InvalidException: 24>), ('CoprocessorError', <ExceptionList.CoprocessorError: 25>), ('LAST_SW', <ExceptionList.LAST_SW: 31>), ('COUNT', <ExceptionList.COUNT: 32>)])¶
-
_member_names_
= ['FIRST_HW', 'LAST_HW', 'InvalidOpcode', 'InvalidInstSet', 'DivideByZero', 'UnalignedAccess', 'PrivilegedInstr', 'DoubleFault', 'MemoryAccess', 'RegisterAccess', 'InvalidException', 'CoprocessorError', 'LAST_SW', 'COUNT']¶
-
_member_type_
¶ alias of
int
-
_value2member_map_
= {0: <ExceptionList.FIRST_HW: 0>, 32: <ExceptionList.COUNT: 32>, 15: <ExceptionList.LAST_HW: 15>, 16: <ExceptionList.InvalidOpcode: 16>, 17: <ExceptionList.InvalidInstSet: 17>, 18: <ExceptionList.DivideByZero: 18>, 19: <ExceptionList.UnalignedAccess: 19>, 20: <ExceptionList.PrivilegedInstr: 20>, 21: <ExceptionList.DoubleFault: 21>, 22: <ExceptionList.MemoryAccess: 22>, 23: <ExceptionList.RegisterAccess: 23>, 24: <ExceptionList.InvalidException: 24>, 25: <ExceptionList.CoprocessorError: 25>, 31: <ExceptionList.LAST_SW: 31>}¶
-
-
exception
ducky.errors.
ExecutionException
(msg, core=None, ip=None)[source]¶ Bases:
exceptions.Exception
Base class for all execution-related exceptions, i.e. exceptions raised as a direct result of requests made by running code. Runnign code can then take care of handling these exceptions, usually by preparing service routines and setting up the
EVT
.Unless said otherwise, the exception is always raised before making any changes in the VM state.
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.
-
runtime_handle
()[source]¶ This method is called by CPU code, to find out if it is possible for runtime to handle the exception, and possibly recover from it. If it is possible, this method should make necessary arrangements, and then return
True
. Many exceptions, e.g. when division by zero was requested, will tell CPU to run exception service routine, and by returningTrue
signal that it’s not necessary to take care of such exception anymore.Return type: bool Returns: True
when it’s no longer necessary for VM code to take care of this exception.
-
class
ducky.errors.
ExecutionException__SimpleESR
[source]¶ Bases:
object
Helper mixin class - as one of parents, it brings to its children very simle - and most of the time sufficient - implementation of runtime_handle method. Such exceptions will tell CPU to run exception service routine with a secific index, specified by class variable
EXCEPTION_INDEX
.The address of the offensive instruction - or the value of
IP
when exception was raised, since there may be exceptions not raised in response to the executed instruction - is passed to CPU as the first argument of ESR.
-
exception
ducky.errors.
IncompatibleSectionFlagsError
(dst_section, src_section, *args, **kwargs)[source]¶ Bases:
ducky.errors.LinkerError
-
exception
ducky.errors.
IncompleteDirectiveError
(**kwargs)[source]¶ Bases:
ducky.errors.AssemblerError
-
exception
ducky.errors.
InvalidExceptionError
(exc_index, *args, **kwargs)[source]¶ Bases:
ducky.errors.ExecutionException__SimpleESR
,ducky.errors.ExecutionException
Raised when requested exception index is invalid (out of bounds).
-
EXCEPTION_INDEX
= 24¶
-
-
exception
ducky.errors.
InvalidFrameError
(saved_sp, current_sp, *args, **kwargs)[source]¶ Bases:
ducky.errors.ExecutionException__SimpleESR
,ducky.errors.ExecutionException
Raised when VM checks each call stack frame to be cleaned before it’s left, and there are some values on stack when
ret
orretint
are executed. In such case, the actualSP
values does not equal to a saved one, and exception is raised.Parameters: - saved_sp (u32_t) –
SP
as saved at the moment the frame was created. - current_sp (u32_t) – current
SP
- saved_sp (u32_t) –
-
exception
ducky.errors.
InvalidInstructionSetError
(inst_set, *args, **kwargs)[source]¶ Bases:
ducky.errors.ExecutionException__SimpleESR
,ducky.errors.ExecutionException
Raised when switch to unknown or invalid instruction set was requested.
Parameters: inst_set (int) – instruction set id. -
EXCEPTION_INDEX
= 17¶
-
-
exception
ducky.errors.
InvalidOpcodeError
(opcode, *args, **kwargs)[source]¶ Bases:
ducky.errors.ExecutionException__SimpleESR
,ducky.errors.ExecutionException
Raised when unknown or invalid opcode is found in instruction.
Parameters: opcode (int) – wrong opcode. -
EXCEPTION_INDEX
= 16¶
-
-
exception
ducky.errors.
InvalidResourceError
(message=None)[source]¶ Bases:
ducky.errors.Error
Raised when an operation was requested on somehow invalid resource.
message
attribute will provide better idea about the fault.
-
exception
ducky.errors.
LinkerError
(message=None)[source]¶ Bases:
ducky.errors.Error
-
exception
ducky.errors.
MemoryAccessError
(access, address, pte, *args, **kwargs)[source]¶ Bases:
ducky.errors.ExecutionException__SimpleESR
,ducky.errors.ExecutionException
Raised when MMU decides the requested memory operation is now allowed, e.g. when page tables are enabled, and corresponding
PTE
denies write access.Parameters: - access (str) –
read
,write
orexecute
. - address (u32_t) – address where memory access shuld have happen.
- pte (ducky.mm.PageTableEntry) –
PTE
guarding this particular memory location.
-
EXCEPTION_INDEX
= 22¶
- access (str) –
-
exception
ducky.errors.
OperandMismatchError
(instr, expected, actual)[source]¶ Bases:
ducky.errors.Error
-
exception
ducky.errors.
PatchTooLargeError
(message=None)[source]¶ Bases:
ducky.errors.LinkerError
-
exception
ducky.errors.
PrivilegedInstructionError
(*args, **kwargs)[source]¶ Bases:
ducky.errors.ExecutionException__SimpleESR
,ducky.errors.ExecutionException
Raised when privileged instruction was about to be executed in non-privileged mode.
-
EXCEPTION_INDEX
= 20¶
-
-
exception
ducky.errors.
RegisterAccessError
(access, reg, *args, **kwargs)[source]¶ Bases:
ducky.errors.ExecutionException__SimpleESR
,ducky.errors.ExecutionException
Raised when instruction tries to access a registerall which is not available for requested operation, e.g. writing into read-only control register will raise this exception.
Parameters: - access (str) –
read
orwrite
. - reg (str) – register name.
-
EXCEPTION_INDEX
= 23¶
- access (str) –
-
exception
ducky.errors.
TooManyLabelsError
(**kwargs)[source]¶ Bases:
ducky.errors.AssemblerError
-
exception
ducky.errors.
UnalignedAccessError
(*args, **kwargs)[source]¶ Bases:
ducky.errors.ExecutionException__SimpleESR
,ducky.errors.ExecutionException
Raised when only properly aligned memory access is allowed, and running code attempts to access memory without honoring this restriction (e.g.
LW
reading from byte-aligned address).-
EXCEPTION_INDEX
= 19¶
-
-
exception
ducky.errors.
UnalignedJumpTargetError
(**kwargs)[source]¶ Bases:
ducky.errors.AssemblerError
-
exception
ducky.errors.
UnknownDestinationSectionError
(src_section, *args, **kwargs)[source]¶ Bases:
ducky.errors.LinkerError
-
exception
ducky.errors.
UnknownFileError
(**kwargs)[source]¶ Bases:
ducky.errors.AssemblerError
-
exception
ducky.errors.
UnknownInstructionError
(**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.LinkerError
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'>]¶ These HDT entries are added automatically.
-
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.
-
ENTRY_HEADER
= [('type', <class 'ctypes.c_ushort'>), ('length', <class 'ctypes.c_ushort'>)]¶
- type (u16_t) – type of entry. See
-
class
ducky.hdt.
HDTEntryTypes
[source]¶ Bases:
enum.IntEnum
Types of different HDT entries.
-
ARGUMENT
= 3¶
-
CPU
= 1¶
-
DEVICE
= 4¶
-
MEMORY
= 2¶
-
UNDEFINED
= 0¶
-
_member_map_
= OrderedDict([('UNDEFINED', <HDTEntryTypes.UNDEFINED: 0>), ('CPU', <HDTEntryTypes.CPU: 1>), ('MEMORY', <HDTEntryTypes.MEMORY: 2>), ('ARGUMENT', <HDTEntryTypes.ARGUMENT: 3>), ('DEVICE', <HDTEntryTypes.DEVICE: 4>)])¶
-
_member_names_
= ['UNDEFINED', 'CPU', 'MEMORY', 'ARGUMENT', 'DEVICE']¶
-
_member_type_
¶ alias of
int
-
_value2member_map_
= {0: <HDTEntryTypes.UNDEFINED: 0>, 1: <HDTEntryTypes.CPU: 1>, 2: <HDTEntryTypes.MEMORY: 2>, 3: <HDTEntryTypes.ARGUMENT: 3>, 4: <HDTEntryTypes.DEVICE: 4>}¶
-
-
class
ducky.hdt.
HDTEntry_Argument
(arg_name, arg_type, arg_value)[source]¶ Bases:
ducky.hdt.HDTEntry
-
MAX_NAME_LENGTH
= 13¶
-
_fields_
= [('type', <class 'ctypes.c_ushort'>), ('length', <class 'ctypes.c_ushort'>), ('name_length', <class 'ctypes.c_ubyte'>), ('value_length', <class 'ctypes.c_ubyte'>), ('name', <class 'ducky.hdt.c_ubyte_Array_13'>), ('value', <class 'ducky.hdt.c_ubyte_Array_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.
-
_fields_
= [('type', <class 'ctypes.c_ushort'>), ('length', <class 'ctypes.c_ushort'>), ('nr_cpus', <class 'ctypes.c_ushort'>), ('nr_cores', <class 'ctypes.c_ushort'>)]¶
-
length
¶ Structure/Union member
-
nr_cores
¶ Structure/Union member
-
nr_cpus
¶ Structure/Union member
-
type
¶ Structure/Union member
-
class
ducky.hdt.
HDTEntry_Device
(logger, name, ident)[source]¶ Bases:
ducky.hdt.HDTEntry
-
ENTRY_HEADER
= [('type', <class 'ctypes.c_ushort'>), ('length', <class 'ctypes.c_ushort'>), ('name_length', <class 'ctypes.c_ubyte'>), ('flags', <class 'ctypes.c_ubyte'>), ('name', <class 'ducky.hdt.c_ubyte_Array_10'>), ('ident', <class 'ducky.hdt.c_ubyte_Array_32'>)]¶
-
MAX_IDENT_LENGTH
= 32¶
-
MAX_NAME_LENGTH
= 10¶
-
-
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. -
_fields_
= [('type', <class 'ctypes.c_ushort'>), ('length', <class 'ctypes.c_ushort'>), ('size', <class 'ctypes.c_uint'>)]¶
-
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.
-
_fields_
= [('magic', <class 'ctypes.c_uint'>), ('entries', <class 'ctypes.c_uint'>), ('length', <class 'ctypes.c_uint'>)]¶
-
entries
¶ Structure/Union member
-
length
¶ Structure/Union member
-
magic
¶ Structure/Union member
-
-
class
ducky.hdt.
HDTStructure
[source]¶ Bases:
_ctypes.Structure
Base class of all HDT structures.
-
_pack_
= 0¶
-
-
ducky.hdt.
HDT_MAGIC
= 1298034544¶ Magic number present in HDT header
-
ducky.hdt.
encode_string
(struct, field, s, max_length)[source]¶ Store string in a structure’s field, and set the corresponding length field properly.
Parameters: - struct (HDTStructure) – structure to modify.
- field (str) – name of field the string should be stored in.
- s (str) – string to encode.
- max_length (int) – maximal number of bytes that can fit into the field.
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¶
-
class
ducky.log.
ColorizedLogFormatter
(format=None)[source]¶ Bases:
ducky.log.LogFormatter
-
_default_format
= '{color_start}[{level}]{color_end} {message}'¶
-
-
class
ducky.log.
LogFormatter
(format=None)[source]¶ Bases:
logging.Formatter
-
_default_format
= '[{level}] {message}'¶
-
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
= 3¶
-
header
¶
-
sections
¶
-
string_table
¶
-
-
class
ducky.mm.binary.
FileFlags
[source]¶ Bases:
ducky.util.Flags
-
_encoding
¶ alias of
FileFlagsEncoding
-
_flags
= ['reserved']¶
-
_labels
= 'M'¶
-
field
= ('reserved', <class 'ctypes.c_ushort'>, 1)¶
-
-
class
ducky.mm.binary.
FileFlagsEncoding
[source]¶ Bases:
_ctypes.Structure
-
_fields_
= [('reserved', <class 'ctypes.c_ushort'>, 1)]¶
-
reserved
¶ Structure/Union member
-
-
class
ducky.mm.binary.
FileHeader
[source]¶ Bases:
_ctypes.Structure
-
_fields_
= [('magic', <class 'ctypes.c_ushort'>), ('version', <class 'ctypes.c_ushort'>), ('flags', <class 'ducky.mm.binary.FileFlagsEncoding'>), ('sections', <class 'ctypes.c_ushort'>)]¶
-
_pack_
= 0¶
-
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
-
_fields_
= [('flags', <class 'ducky.mm.binary.RelocFlagsEncoding'>), ('name', <class 'ctypes.c_uint'>), ('patch_add', <class 'ctypes.c_uint'>), ('patch_address', <class 'ctypes.c_uint'>), ('patch_section', <class 'ctypes.c_ubyte'>), ('patch_offset', <class 'ctypes.c_ubyte'>), ('patch_size', <class 'ctypes.c_ubyte'>)]¶
-
_pack_
= 0¶
-
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
-
_encoding
¶ alias of
RelocFlagsEncoding
-
_flags
= ['relative', 'inst_aligned']¶
-
_labels
= 'RI'¶
-
field
= ('inst_aligned', <class 'ctypes.c_ushort'>, 1)¶
-
-
class
ducky.mm.binary.
RelocFlagsEncoding
[source]¶ Bases:
_ctypes.Structure
-
_fields_
= [('relative', <class 'ctypes.c_ushort'>, 1), ('inst_aligned', <class 'ctypes.c_ushort'>, 1)]¶
-
inst_aligned
¶ Structure/Union member
-
relative
¶ Structure/Union member
-
-
class
ducky.mm.binary.
Section
(parent, index, name=None, header=None, payload=None)[source]¶ Bases:
object
-
header
¶
-
name
¶
-
payload
¶
-
-
class
ducky.mm.binary.
SectionFlags
[source]¶ Bases:
ducky.util.Flags
-
_encoding
¶ alias of
SectionFlagsEncoding
-
_flags
= ['readable', 'writable', 'executable', 'loadable', 'bss', 'globally_visible']¶
-
_labels
= 'RWXLBG'¶
-
field
= ('globally_visible', <class 'ctypes.c_ubyte'>, 1)¶
-
-
class
ducky.mm.binary.
SectionFlagsEncoding
[source]¶ Bases:
_ctypes.Structure
-
_fields_
= [('readable', <class 'ctypes.c_ubyte'>, 1), ('writable', <class 'ctypes.c_ubyte'>, 1), ('executable', <class 'ctypes.c_ubyte'>, 1), ('loadable', <class 'ctypes.c_ubyte'>, 1), ('bss', <class 'ctypes.c_ubyte'>, 1), ('globally_visible', <class 'ctypes.c_ubyte'>, 1)]¶
-
bss
¶ Structure/Union member
-
executable
¶ Structure/Union member
-
globally_visible
¶ Structure/Union member
-
loadable
¶ Structure/Union member
-
readable
¶ Structure/Union member
-
writable
¶ Structure/Union member
-
-
class
ducky.mm.binary.
SectionHeader
[source]¶ Bases:
_ctypes.Structure
-
_fields_
= [('index', <class 'ctypes.c_ubyte'>), ('name', <class 'ctypes.c_uint'>), ('type', <class 'ctypes.c_ubyte'>), ('flags', <class 'ducky.mm.binary.SectionFlagsEncoding'>), ('padding', <class 'ctypes.c_ubyte'>), ('base', <class 'ctypes.c_uint'>), ('data_size', <class 'ctypes.c_uint'>), ('file_size', <class 'ctypes.c_uint'>), ('offset', <class 'ctypes.c_uint'>)]¶
-
_pack_
= 0¶
-
base
¶ Structure/Union member
-
data_size
¶ Structure/Union member
-
file_size
¶ Structure/Union member
-
flags
¶ Structure/Union member
-
index
¶ 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
-
PROGBITS
= 1¶
-
RELOC
= 4¶
-
STRINGS
= 3¶
-
SYMBOLS
= 2¶
-
UNKNOWN
= 0¶
-
_member_map_
= OrderedDict([('UNKNOWN', <SectionTypes.UNKNOWN: 0>), ('PROGBITS', <SectionTypes.PROGBITS: 1>), ('SYMBOLS', <SectionTypes.SYMBOLS: 2>), ('STRINGS', <SectionTypes.STRINGS: 3>), ('RELOC', <SectionTypes.RELOC: 4>)])¶
-
_member_names_
= ['UNKNOWN', 'PROGBITS', 'SYMBOLS', 'STRINGS', 'RELOC']¶
-
_member_type_
¶ alias of
int
-
_value2member_map_
= {0: <SectionTypes.UNKNOWN: 0>, 1: <SectionTypes.PROGBITS: 1>, 2: <SectionTypes.SYMBOLS: 2>, 3: <SectionTypes.STRINGS: 3>, 4: <SectionTypes.RELOC: 4>}¶
-
-
class
ducky.mm.binary.
SymbolDataTypes
[source]¶ Bases:
enum.IntEnum
-
ASCII
= 5¶
-
BYTE
= 3¶
-
CHAR
= 2¶
-
FUNCTION
= 6¶
-
INT
= 0¶
-
SHORT
= 1¶
-
STRING
= 4¶
-
UNKNOWN
= 7¶
-
_member_map_
= OrderedDict([('INT', <SymbolDataTypes.INT: 0>), ('SHORT', <SymbolDataTypes.SHORT: 1>), ('CHAR', <SymbolDataTypes.CHAR: 2>), ('BYTE', <SymbolDataTypes.BYTE: 3>), ('STRING', <SymbolDataTypes.STRING: 4>), ('ASCII', <SymbolDataTypes.ASCII: 5>), ('FUNCTION', <SymbolDataTypes.FUNCTION: 6>), ('UNKNOWN', <SymbolDataTypes.UNKNOWN: 7>)])¶
-
_member_names_
= ['INT', 'SHORT', 'CHAR', 'BYTE', 'STRING', 'ASCII', 'FUNCTION', 'UNKNOWN']¶
-
_member_type_
¶ alias of
int
-
_value2member_map_
= {0: <SymbolDataTypes.INT: 0>, 1: <SymbolDataTypes.SHORT: 1>, 2: <SymbolDataTypes.CHAR: 2>, 3: <SymbolDataTypes.BYTE: 3>, 4: <SymbolDataTypes.STRING: 4>, 5: <SymbolDataTypes.ASCII: 5>, 6: <SymbolDataTypes.FUNCTION: 6>, 7: <SymbolDataTypes.UNKNOWN: 7>}¶
-
-
class
ducky.mm.binary.
SymbolEntry
[source]¶ Bases:
_ctypes.Structure
-
_fields_
= [('flags', <class 'ducky.mm.binary.SymbolFlagsEncoding'>), ('name', <class 'ctypes.c_uint'>), ('address', <class 'ctypes.c_uint'>), ('size', <class 'ctypes.c_uint'>), ('section', <class 'ctypes.c_ubyte'>), ('type', <class 'ctypes.c_ubyte'>), ('filename', <class 'ctypes.c_uint'>), ('lineno', <class 'ctypes.c_uint'>)]¶
-
_pack_
= 0¶
-
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
-
_encoding
¶ alias of
SymbolFlagsEncoding
-
_flags
= ['globally_visible']¶
-
_labels
= 'G'¶
-
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
= 3¶
-
FREE
= 4¶
-
MMAP
= 6¶
-
UNMMAP
= 7¶
-
UNUSED
= 5¶
-
_member_map_
= OrderedDict([('ALLOC', <MMOperationList.ALLOC: 3>), ('FREE', <MMOperationList.FREE: 4>), ('UNUSED', <MMOperationList.UNUSED: 5>), ('MMAP', <MMOperationList.MMAP: 6>), ('UNMMAP', <MMOperationList.UNMMAP: 7>)])¶
-
_member_names_
= ['ALLOC', 'FREE', 'UNUSED', 'MMAP', 'UNMMAP']¶
-
_member_type_
¶ alias of
int
-
_value2member_map_
= {3: <MMOperationList.ALLOC: 3>, 4: <MMOperationList.FREE: 4>, 5: <MMOperationList.UNUSED: 5>, 6: <MMOperationList.MMAP: 6>, 7: <MMOperationList.UNMMAP: 7>}¶
-
-
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
.-
_MemoryController__alloc_page
(index)¶ Allocate new anonymous page for usage. The first available index is used.
Be aware that this method does NOT check if page is already allocated. If it is, it is just overwritten by new anonymous page.
Parameters: index (int) – index of requested page. Returns: newly reserved page. Return type: ducky.mm.AnonymousMemoryPage
-
_MemoryController__remove_page
(pg)¶ Removes page object for a specific memory page.
Parameters: pg (ducky.mm.MemoryPage) – page to be removed
-
_MemoryController__set_page
(pg)¶ Install page object for a specific memory page.
Parameters: pg (ducky.mm.MemoryPage) – page to be installed Returns: installed page Return type: ducky.mm.MemoryPage
-
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.
-
class
ducky.mm.
PageTableEntry
[source]¶ Bases:
ducky.util.Flags
-
DIRTY
= 8¶
-
EXECUTE
= 4¶
-
READ
= 1¶
-
WRITE
= 2¶
-
_flags
= ['read', 'write', 'execute', 'dirty']¶
-
_labels
= 'RWXD'¶
-
-
class
ducky.mm.
VirtualMemoryPage
(controller, index)[source]¶ Bases:
ducky.mm.MemoryPage
Memory page without any real storage backend.
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
-
_asdict
()¶ Return a new OrderedDict which maps field names to their values
-
_fields
= ('on_read', 'on_write', 'on_error')¶
-
classmethod
_make
(iterable, new=<built-in method __new__ of type object at 0x906d60>, len=<built-in function len>)¶ Make a new FDCallbacks object from a sequence or iterable
-
_replace
(_self, **kwds)¶ Return a new FDCallbacks object replacing specified fields with new values
-
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
-
_abc_cache
= <_weakrefset.WeakSet object>¶
-
_abc_negative_cache
= <_weakrefset.WeakSet object>¶
-
_abc_negative_cache_version
= 29¶
-
_abc_registry
= <_weakrefset.WeakSet object>¶
-
-
class
ducky.streams.
FDOutputStream
(machine, fd, **kwargs)[source]¶ Bases:
ducky.streams.OutputStream
-
_abc_cache
= <_weakrefset.WeakSet object>¶
-
_abc_negative_cache
= <_weakrefset.WeakSet object>¶
-
_abc_negative_cache_version
= 29¶
-
_abc_registry
= <_weakrefset.WeakSet object>¶
-
-
class
ducky.streams.
FileInputStream
(machine, f, **kwargs)[source]¶ Bases:
ducky.streams.InputStream
-
_abc_cache
= <_weakrefset.WeakSet object>¶
-
_abc_negative_cache
= <_weakrefset.WeakSet object>¶
-
_abc_negative_cache_version
= 29¶
-
_abc_registry
= <_weakrefset.WeakSet object>¶
-
-
class
ducky.streams.
FileOutputStream
(machine, f, **kwargs)[source]¶ Bases:
ducky.streams.OutputStream
-
_abc_cache
= <_weakrefset.WeakSet object>¶
-
_abc_negative_cache
= <_weakrefset.WeakSet object>¶
-
_abc_negative_cache_version
= 29¶
-
_abc_registry
= <_weakrefset.WeakSet object>¶
-
-
class
ducky.streams.
InputStream
(machine, desc, stream=None, fd=None, close=True, allow_close=True)[source]¶ Bases:
ducky.streams.Stream
-
_abc_cache
= <_weakrefset.WeakSet object>¶
-
_abc_negative_cache
= <_weakrefset.WeakSet object>¶
-
_abc_negative_cache_version
= 29¶
-
_abc_registry
= <_weakrefset.WeakSet object>¶
-
-
class
ducky.streams.
MethodInputStream
(machine, desc, **kwargs)[source]¶ Bases:
ducky.streams.InputStream
-
_abc_cache
= <_weakrefset.WeakSet object>¶
-
_abc_negative_cache
= <_weakrefset.WeakSet object>¶
-
_abc_negative_cache_version
= 29¶
-
_abc_registry
= <_weakrefset.WeakSet object>¶
-
-
class
ducky.streams.
MethodOutputStream
(machine, desc, **kwargs)[source]¶ Bases:
ducky.streams.OutputStream
-
_abc_cache
= <_weakrefset.WeakSet object>¶
-
_abc_negative_cache
= <_weakrefset.WeakSet object>¶
-
_abc_negative_cache_version
= 29¶
-
_abc_registry
= <_weakrefset.WeakSet object>¶
-
-
class
ducky.streams.
OutputStream
(machine, desc, stream=None, fd=None, close=True, allow_close=True)[source]¶ Bases:
ducky.streams.Stream
-
_abc_cache
= <_weakrefset.WeakSet object>¶
-
_abc_negative_cache
= <_weakrefset.WeakSet object>¶
-
_abc_negative_cache_version
= 29¶
-
_abc_registry
= <_weakrefset.WeakSet object>¶
-
-
class
ducky.streams.
StderrStream
(machine)[source]¶ Bases:
ducky.streams.OutputStream
-
_abc_cache
= <_weakrefset.WeakSet object>¶
-
_abc_negative_cache
= <_weakrefset.WeakSet object>¶
-
_abc_negative_cache_version
= 29¶
-
_abc_registry
= <_weakrefset.WeakSet object>¶
-
-
class
ducky.streams.
StdinStream
(machine, **kwargs)[source]¶ Bases:
ducky.streams.InputStream
-
_abc_cache
= <_weakrefset.WeakSet object>¶
-
_abc_negative_cache
= <_weakrefset.WeakSet object>¶
-
_abc_negative_cache_version
= 29¶
-
_abc_registry
= <_weakrefset.WeakSet object>¶
-
-
class
ducky.streams.
StdoutStream
(machine)[source]¶ Bases:
ducky.streams.OutputStream
-
_abc_cache
= <_weakrefset.WeakSet object>¶
-
_abc_negative_cache
= <_weakrefset.WeakSet object>¶
-
_abc_negative_cache_version
= 29¶
-
_abc_registry
= <_weakrefset.WeakSet object>¶
-
-
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.
-
_abc_cache
= <_weakrefset.WeakSet object>¶
-
_abc_negative_cache
= <_weakrefset.WeakSet object>¶
-
_abc_negative_cache_version
= 29¶
-
_abc_registry
= <_weakrefset.WeakSet object>¶
-
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.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.
-
_machines
= []¶
-
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. -
_abc_cache
= <_weakrefset.WeakSet object>¶
-
_abc_negative_cache
= <_weakrefset.WeakSet object>¶
-
_abc_negative_cache_version
= 39¶
-
_abc_registry
= <_weakrefset.WeakSet object>¶
-
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. -
_abc_cache
= <_weakrefset.WeakSet object>¶
-
_abc_negative_cache
= <_weakrefset.WeakSet object>¶
-
_abc_negative_cache_version
= 39¶
-
_abc_registry
= <_weakrefset.WeakSet object>¶
-
-
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.
StringTable
(buff=None)[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.
-
buff
¶ Serialize internal string table to a stream of bytes.
-