Tags: programming, gsoc, 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!
was merged, prompting the release of version
This was followed up by
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 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
MachOFile0#cpusubtype) returned (long and unwieldy) string literals as
representations of the integer constants, while others (like
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
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
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
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
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
FatFile object for calculations
not strictly restricted to the data in a given load command.
Thanks for reading!