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.