diff options
author | Alex Deymo <deymo@chromium.org> | 2014-03-25 17:53:56 -0700 |
---|---|---|
committer | chrome-internal-fetch <chrome-internal-fetch@google.com> | 2014-03-26 05:34:44 +0000 |
commit | 032e772f76a6cd0b4caf1af7bd02dd81af2dc7dd (patch) | |
tree | 73f75c03ae5c589e8bfe2781c4e4faa8b4701113 /utils.cc | |
parent | 04f2b380d4707a3903098a7459443c9509745943 (diff) |
Log the file format of cros_install on postinstall action
This patch adds a new function to utils which determines the format
of a file based on magic constants on the header and returns a
human-readable description of it. This currently only supports ELF
files and is used to log the file format of the cros_install
binary on post-install.
BUG=chromium:356187
TEST=Unittests.
Change-Id: Ie6e91c3f5fa398c39894704db9071489560a8ff7
Reviewed-on: https://chromium-review.googlesource.com/191609
Tested-by: Alex Deymo <deymo@chromium.org>
Reviewed-by: Don Garrett <dgarrett@chromium.org>
Commit-Queue: Alex Deymo <deymo@chromium.org>
Diffstat (limited to 'utils.cc')
-rw-r--r-- | utils.cc | 82 |
1 files changed, 82 insertions, 0 deletions
@@ -56,6 +56,11 @@ namespace { // one second. const int kUnmountMaxNumOfRetries = 5; const int kUnmountRetryIntervalInMicroseconds = 200 * 1000; // 200 ms + +// Number of bytes to read from a file to attempt to detect its contents. Used +// in GetFileFormat. +const int kGetFileFormatMaxHeaderSize = 32; + } // namespace namespace utils { @@ -665,6 +670,83 @@ bool GetFilesystemSizeFromFD(int fd, return true; } +// Tries to parse the header of an ELF file to obtain a human-readable +// description of it on the |output| string. +static bool GetFileFormatELF(const char* buffer, size_t size, string* output) { + // 0x00: EI_MAG - ELF magic header, 4 bytes. + if (size < 4 || memcmp(buffer, "\x7F""ELF", 4) != 0) + return false; + *output = "ELF"; + + // 0x04: EI_CLASS, 1 byte. + if (size < 0x04 + 1) + return true; + switch (buffer[4]) { + case 1: + *output += " 32-bit"; + break; + case 2: + *output += " 64-bit"; + break; + default: + *output += " ?-bit"; + } + + // 0x05: EI_DATA, endianness, 1 byte. + if (size < 0x05 + 1) + return true; + char ei_data = buffer[5]; + switch (ei_data) { + case 1: + *output += " little-endian"; + break; + case 2: + *output += " big-endian"; + break; + default: + *output += " ?-endian"; + // Don't parse anything after the 0x10 offset if endianness is unknown. + return true; + } + + // 0x12: e_machine, 2 byte endianness based on ei_data + if (size < 0x12 + 2) + return true; + uint16 e_machine = *reinterpret_cast<const uint16*>(buffer+0x12); + // Fix endianess regardless of the host endianess. + if (ei_data == 1) + e_machine = le16toh(e_machine); + else + e_machine = be16toh(e_machine); + + switch (e_machine) { + case 0x03: + *output += " x86"; + break; + case 0x28: + *output += " arm"; + break; + case 0x3E: + *output += " x86-64"; + break; + default: + *output += " unknown-arch"; + } + return true; +} + +string GetFileFormat(const string& path) { + vector<char> buffer; + if (!ReadFileChunkAndAppend(path, 0, kGetFileFormatMaxHeaderSize, &buffer)) + return "File not found."; + + string result; + if (GetFileFormatELF(buffer.data(), buffer.size(), &result)) + return result; + + return "data"; +} + bool GetBootloader(BootLoader* out_bootloader) { // For now, hardcode to syslinux. *out_bootloader = BootLoader_SYSLINUX; |