5.2 poke Maps

As we have seen mapping variables is a very powerful, general and flexible mean to edit stored binary data in one or more IO spaces. However it is easy to lose track of where the variables are mapped and, ideally speaking, we would want to have a mean to refer to, say, the “ELF header”, and get the header as a mapped value regardless of what specific file we are editing. Sort of a “meta variable”. GNU poke provides a way to do this: maps.

A map can be conceived as a sort of “view” that can be applied to a given IO space. Maps have entries, which are values mapped at some given offset, under certain conditions. For example, we have seen an ELF file contains, among other things, a header at the beginning of the file and a table of section headers of certain size and located at certain location determined by the header. These would be two entries of a so-called ELF map.

poke maps are defined in map files. These files use the .map extension. A map file self.map (for sectioned/simple elf) defining the view of an ELF file as a header and a table of section header would look like this:

/* self.map - map file for a simplified view of an ELF file.  */

load elf;

%%

%entry
%name ehdr
%type Elf64_Ehdr
%offset 0#B

%entry
%name shdr
%type Elf64_Shdr[(Elf64_Ehdr @ 0#B).e_shnum]
%condition (Elf64_Ehdr @ 0#B).e_shnum > 0
%offset (Elf64_Ehdr @ 0#B).e_shoff

This map file defines a view of an ELF file as a header entry ehdr and an entry with a table of section headers shdr.

The first section of the file, which spans until the separator line containing %%, is arbitrary Poke code which as we shall see, gets evaluated before the map entries are processed. This is called the map "prologue". In this case, the prologue contains a comment explaining the purpose of the file, and a single statement load that loads the elf.pk pickle, since the entries below use definitions like Elf64_Ehdr that are defined by that pickle. The prologue is useful to define Poke functions and other entities that are then used in the definitions of the entries.

A separator line containing only %% separates the prologue from the next section, which is a list of entries definitions. Each entry definition starts with a line %entry, and has the following attributes:

%name

Like ehdr and shdr. These names should follow the same rules than Poke variables, but as we shall see later, map entries are not Poke variables. This attribute is mandatory.

%type

This can be any Poke expression denoting a type, like int, Elf64_Ehdr or Elf64_Shdr[(Elf64_Ehdr @ 0#B).e_shnum]. This attribute is mandatory.

%condition

If specified, will determine whether to include the entry in the map. In the example above, the map will have an entry shdr only if the ELF file has one or more sections. Any Poke expression evaluating to a boolean can be used as conditions. This attribute is optional: entries not having a condition will always be included in the map.

%offset

Offset in the IO space where the entry will be mapped. Any Poke expression evaluating to an offset can be used as entry offset. This attribute is mandatory.