-
Notifications
You must be signed in to change notification settings - Fork 0
File Types
Embedding metadata is supported for hex and elf formats: this language implements a thin wrapper on the debug/elf
go package, and an ihex parser to make it possible to write and read from and to a file with an API that gives random
access capabilities to the user.
Files can be accessed in order to extract data from them and manipulating their contents.
When you access a file, its contents get loaded in memory and the os handle gets closed. You can manipulate the data and then choose to save the file onto the original one. You can interact with files with the following builtin functions:
-
open(filename: str, type: str) -> file_handle: open the file with the passed name, type can behex,elf, orbytes. -
save(file_handle): saves the changes to the file on the fs. -
as_bytes(file_handle) -> []int: returns a copy of the file contents as an array of ints.
Consider the following simple C program:
int main(void) {
volatile int c = 0;
c++;
c *= 2;
while(1);
}And let's compile it for a generic avr mcu:
avr-gcc -O0 -o test.elf main.c
avr-objcopy -Oihex test.elf test.hexWe can then manipulate the hex file as follows:
>>> var h = try open("test.hex", "hex")
>>> print(h) // <- This prints the contents of the hex file as a string
:10000000CF93DF9300D0CDB7DEB71A8219828981F2
:100010009A8101969A83898389819A81880F991F91
:060020009A838983FFCFE3
:00000001FF
// Print information related to the hex file
>>> print("Number of records:", h.size())
Number of records: 4
>>> print("Actual data contained within the data records:", h.binary_size())
Actual data contained within the data records: 38
// Read n bytes (1st param) starting from position m (0th param)
>>> print(h.read_at(0, 16))
[207, 147, 223, 147, 0, 208, 205, 183, 222, 183, 26, 130, 25, 130, 137, 129]
// Write the array at the specified position
>>> try h.write_at(0, from_hex("deadbeef"))
>>> var first_word = try h.read_at(0, 16)
>>> print(first_word)
[222, 173, 190, 239, 0, 208, 205, 183, 222, 183, 26, 130, 25, 130, 137, 129]
>>> print(first_word, hex(first_word))
[222, 173, 190, 239, 0, 208, 205, 183, 222, 183, 26, 130, 25, 130, 137, 129] deadbeef00d0cdb7deb71a8219828981
// Print the contents of the hex file as a bytes array
>>> print(as_bytes(h))
[58, 49, 48, 48, 48, 48, 48, 48, 48, 100, 101, 97, 100, 98, 101, 101, 102, 48, 48, 68, 48, 67, 68, 66, 55, 68, 69, 66, 55, 49, 65, 56, 50, 49, 57, 56, 50, 56, 57, 56, 49, 56, 101, 13, 10, 58, 49, 48, 48, 48, 49, 48, 48, 48, 57, 65, 56, 49, 48, 49, 57, 54, 57, 65, 56, 51, 56, 57, 56, 51, 56, 57, 56, 49, 57, 65, 56, 49, 56, 56, 48, 70, 57, 57, 49, 70, 57, 49, 13, 10, 58, 48, 54, 48, 48, 50, 48, 48, 48, 57, 65, 56, 51, 56, 57, 56, 51, 70, 70, 67, 70, 69, 51, 13, 10, 58, 48, 48, 48, 48, 48, 48, 48, 49, 70, 70, 13, 10]
// Read the i-th record as a string
>>> print(try h.record(0))
:10000000DEADBEEF00D0CDB7DEB71A82198289818E
// Dump the written contents back to the file
>>> save(h)
Consider the following simple c file:
static const unsigned char
data[256] __attribute__((section(".embmetadata")));
int main(void) {
while(1) {}
}And let's compile it for a generic avr mcu:
avr-gcc -O0 -o test.elf main.cWe can then manipulate the hex file as follows:
var e = try open("test.elf", "elf")
print(e) // <- This prints the elf object info
ElfFile(@test.elf) {
Sections: [ .text .embmetadata .data .comment .symtab .strtab .shstrtab ]
}
// Check if the section with the given name exists
if e.has_section(".embmetadata") {
print("'.embmetadata' section found in test.elf")
}
'.embmetadata' section found in test.elf
// This print will not get executed
if e.has_section(".test") {
print("'.test' section found in test.elf")
}
// Print each section
print(e.sections())
[, .text, .embmetadata, .data, .comment, .symtab, .strtab, .shstrtab]
// You can access the address of a section
print(".embetadata, addr:", hex(e.section_address(".embmetadata")))
.embetadata, addr: 0x0a
// And its size
print(".embetadata, size: ", hex(e.section_size(".embmetadata")))
.embetadata, size: 0x10
// Read the contents of the given section and returns a copy as an array of ints
print(try e.read_section(".embmetadata"))
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
// Write some data (an array of ints here) into the given section at offset 0
try e.write_section(".embmetadata", from_hex("cafe0102"), 0)
print(try e.read_section(".embmetadata"))
[202, 254, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
print(hex(try e.read_section(".embmetadata")))
cafe0102000000000000000000000000
// Write some data (an array of ints here) into the given section at a non-zero offset
try e.write_section(".embmetadata", from_hex("beef0405"), 6)
print(try e.read_section(".embmetadata"))
[202, 254, 1, 2, 0, 0, 190, 239, 4, 5, 0, 0, 0, 0, 0, 0]
print(hex(try e.read_section(".embmetadata")))
cafe01020000beef0405000000000000
print(as_bytes(h)) // prints [127, 69, 76, 70, 1, 1, 1, 0, 0, 0, 0, 0, 0, ... ]
// Dump the written contents back to the file
save(e)
A generic file can be manipulated as a stream of bytes:
// test is a text file containing the following contents:
// "hello world!"
var b = try open("test", "bytes")
print(b) // prints the bytes object
// Read 5 bytes from the file at position 0
print(b.read_at(0, 5)) // prints [32, 119, 111, 114, 108]
// Write some data (an array of ints here) at position 0
try b.write_at(0, [1, 2, 3])
print(b.read_at(0, 5)) // prints [1, 2, 3, 114, 108]
// Dump the written contents back to the file
save(e)