Jun 26, 2016 Tags: gsoc, programming, ruby, ruby-macho
For a quick background, see the last post in this series.
As of the last two weeks:
PPC parsing is here, and live by default in Homebrew!
…on test-bot
, anyways.
ruby-macho/24
was merged, prompting the release of version
0.2.3.
This was followed up by
0.2.4,
currently the latest version (and primarily just an expansion of the test
suite and known CPU types/sub-types). This version was then merged into
Homebrew via brew/378,
along with some tweaks to the glue code. With this, Homebrew is now
successfully using ruby-macho by default on test-bot
instances (i.e.,
the CI)!
The API is getting cleaner!
Previously, ruby-macho’s public interface was a bit of a mixed bag in terms
of style and usability. Many methods (like MachOFile#cputype
and
MachOFile0#cpusubtype
) returned (long and unwieldy) string literals as
representations of the integer constants, while others (like MachOFile#[]
and Section#flag?
) expected symbols as parameters. This is finally
(slowly) improving, with MachOFile#filetype
returning a new friendly
symbol for each Mach-O type instead of the old "MH_*"
stringified constant
names. These changes can be seen in progress in
ruby-macho/29 and merged
as ruby-macho/aeea94b.
Load commands are getting DRYer!
One of the ugliest features of ruby-macho were the load command definitions. Because each load command type has different fields following a group of common ones, their constructors would end up looking something like 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
# @api private
def initialize(raw_data, endianness, offset, cmd, cmdsize, ilocalsym,
nlocalsym, iextdefsym, nextdefsym, iundefsym, nundefsym, tocoff,
ntoc, modtaboff, nmodtab, extrefsymoff, nextrefsyms, indirectsymoff,
nindirectsyms, extreloff, nextrel, locreloff, nlocrel)
super(raw_data, endianness, offset, cmd, cmdsize)
@ilocalsym = ilocalsym
@nlocalsym = nlocalsym
@iextdefsym = iextdefsym
@nextdefsym = nextdefsym
@iundefsym = iundefsym
@nundefsym = nundefsym
@tocoff = tocoff
@ntoc = ntoc
@modtaboff = modtaboff
@nmodtab = nmodtab
@extrefsymoff = extrefsymoff
@nextrefsyms = nextrefsyms
@indirectsymoff = indirectsymoff
@nindirectsyms = nindirectsyms
@extreloff = extreloff
@nextrel = nextrel
@locreloff = locreloff
@nlocrel = nlocrel
end
These fields are auto-populated by LoadCommand.new_from_bin
, but even
still are an eyesore and repeat much of the same (general) information
over and over. Since fields like raw_data
and offset
are not
constituents of the load command itself but rather metadata about the
command (namely, its source blob and the offset at which it begins in that
blob), the decision was made to group them - along with an endianness
symbol - into a single MachOView
class. Instances of this class then
represent an abstract “view” into the Mach-O data associated with some
ruby-macho class or structure. As such, constructors like the above trade
in three arguments for one:
1
2
3
4
5
6
7
8
# @api private
def initialize(view, cmd, cmdsize, ilocalsym,
nlocalsym, iextdefsym, nextdefsym, iundefsym, nundefsym, tocoff,
ntoc, modtaboff, nmodtab, extrefsymoff, nextrefsyms, indirectsymoff,
nindirectsyms, extreloff, nextrel, locreloff, nlocrel)
super(view, cmd, cmdsize)
# ...
end
It’s not a huge reduction, but it’s certainly a step in the right direction! These changes can be seen in progress in ruby-macho/30 and merged as ruby-macho/a62c23a.
Support for complex inspection is on the horizon!
The introduction of MachOView
paves the way for more robust Mach-O
inspection, as dedicated inspection classes declared within individual load
commands can now rely on a uniform view into the binary data that their
command references. Currently,
ruby-macho/32 is the only
example of this new interface’s advantages, although richer support for
data referenced by sections and dyld
commands will be coming shortly. This
also has the added benefit of reducing the current pattern of returning
control flow to the current MachOFile
or FatFile
object for calculations
not strictly restricted to the data in a given load command.
Thanks for reading!
- William