2022-12-24 02:21:54 +00:00
|
|
|
# Usage of the C API
|
|
|
|
|
|
|
|
## Simple example to disassemble a word
|
|
|
|
|
|
|
|
```c
|
|
|
|
#include "rabbitizer.h"
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
int main() {
|
|
|
|
RabbitizerInstruction instr;
|
|
|
|
uint32_t word = 0x8D4A7E18;
|
|
|
|
uint32_t vram = 0x80000000;
|
|
|
|
char *buffer;
|
|
|
|
size_t bufferSize;
|
|
|
|
|
|
|
|
RabbitizerInstruction_init(&instr, word, vram);
|
|
|
|
RabbitizerInstruction_processUniqueId(&instr);
|
|
|
|
|
|
|
|
bufferSize = RabbitizerInstruction_getSizeForBuffer(&instr, 0, 0);
|
|
|
|
buffer = malloc(bufferSize + 1);
|
|
|
|
|
|
|
|
RabbitizerInstruction_disassemble(&instr, buffer, NULL, 0, 0);
|
|
|
|
|
|
|
|
printf("%s\n", buffer);
|
|
|
|
|
|
|
|
free(buffer);
|
|
|
|
RabbitizerInstruction_destroy(&instr);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
Compiling and running the above C code prints the following:
|
|
|
|
|
|
|
|
```mips
|
|
|
|
lw $t2, 0x7E18($t2)
|
|
|
|
```
|
|
|
|
|
|
|
|
Please note many safe-guards were removed from this example for simplicity, like
|
|
|
|
checking if `malloc` returned a `NULL` pointer.
|
|
|
|
|
|
|
|
Let's break up the example and explain each part:
|
|
|
|
|
|
|
|
1. The stack
|
|
|
|
|
|
|
|
The `RabbitizerInstruction` type is the type `rabbitizer` uses to represent an
|
|
|
|
instruction. It is a simple struct which doesn't need dynamic memory
|
|
|
|
allocation of any kind, so it can be declared as an automatic variable and live
|
|
|
|
in the stack, without worrying about pointers and such.
|
|
|
|
|
|
|
|
The other stack variables should be self-explanatory. `word` is a 32-bit word
|
|
|
|
representing a raw MIPS instruction (spoiler, it is an `lw`). `rabbitizer`
|
|
|
|
needs to know the `vram` address of the instruction it is decoding, so we
|
|
|
|
initialize with a place-holder one. `buffer` and `bufferSize` will be used for
|
|
|
|
storing the disassembled string.
|
|
|
|
|
|
|
|
```c
|
|
|
|
int main() {
|
|
|
|
RabbitizerInstruction instr;
|
|
|
|
uint32_t word = 0x8D4A7E18;
|
|
|
|
uint32_t vram = 0x80000000;
|
|
|
|
char *buffer;
|
|
|
|
size_t bufferSize;
|
|
|
|
```
|
|
|
|
|
|
|
|
2. Initializing
|
|
|
|
|
|
|
|
To initialize our `instr` we need to call the pair `RabbitizerInstruction_init`
|
|
|
|
and `RabbitizerInstruction_processUniqueId`. `RabbitizerInstruction_init`
|
|
|
|
initialises all the members of the struct so it doesn't contain garbage data
|
|
|
|
anymore, while `RabbitizerInstruction_processUniqueId` does the heavy lifting of
|
|
|
|
identifying the actual instruction id out of the `word` we passed.
|
|
|
|
|
|
|
|
A `RabbitizerInstruction` variable is not considered fully initialized until it
|
|
|
|
has been passed to this pair of functions.
|
|
|
|
|
|
|
|
```c
|
|
|
|
RabbitizerInstruction_init(&instr, word, vram);
|
|
|
|
RabbitizerInstruction_processUniqueId(&instr);
|
|
|
|
```
|
|
|
|
|
|
|
|
3. Disassembling into a string
|
|
|
|
|
2022-12-24 13:15:49 +00:00
|
|
|
To disassemble the passed word as a string we can call
|
2022-12-24 02:21:54 +00:00
|
|
|
`RabbitizerInstruction_disassemble`. This function expects a `char` buffer to
|
|
|
|
fill, which should have enough space to hold the resulting string. To know how
|
|
|
|
big this buffer needs to be we should use the
|
|
|
|
`RabbitizerInstruction_getSizeForBuffer` function which calculates a size big
|
|
|
|
enough to hold the disassembled string for the passed instruction (without
|
2022-12-24 13:15:49 +00:00
|
|
|
taking into account the finalizing NUL character, similar to how `strlen`
|
|
|
|
behaves).
|
2022-12-24 02:21:54 +00:00
|
|
|
|
|
|
|
With this information we can just `malloc` our buffer and call
|
|
|
|
`RabbitizerInstruction_disassemble` to get our disassembled instruction.
|
|
|
|
|
|
|
|
(Ignore the extra `0` and `NULL` arguments for now, they will be discussed later)
|
|
|
|
|
|
|
|
```c
|
|
|
|
bufferSize = RabbitizerInstruction_getSizeForBuffer(&instr, 0, 0);
|
|
|
|
buffer = malloc(bufferSize + 1);
|
|
|
|
|
|
|
|
RabbitizerInstruction_disassemble(&instr, buffer, NULL, 0, 0);
|
|
|
|
```
|
|
|
|
|
|
|
|
4. Printing
|
|
|
|
|
|
|
|
Not much to say here, just print the disassembled instruction to `stdout`.
|
|
|
|
|
|
|
|
```c
|
|
|
|
printf("%s\n", buffer);
|
|
|
|
```
|
|
|
|
|
|
|
|
5. Clean-up
|
|
|
|
|
|
|
|
Finally since we know we won't be using the produced string or the instruction
|
|
|
|
we just `free` and `RabbitizerInstruction_destroy` them.
|
|
|
|
|
2022-12-24 13:15:49 +00:00
|
|
|
As a curiosity, `RabbitizerInstruction_destroy` currently does nothing, but
|
|
|
|
exists in case some destruction is needed in the future, so it recommended to
|
|
|
|
call this function as a future-proof method.
|
|
|
|
|
2022-12-24 02:21:54 +00:00
|
|
|
```c
|
|
|
|
free(buffer);
|
|
|
|
RabbitizerInstruction_destroy(&instr);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
```
|