mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-09 14:06:33 +00:00
Add MachOImageSegmentReader.
This is part of a family of classes whose chief entry point is MachOImageReader. MachOImageReader depends on this class to read segments, so this one is landing first. The bulk of this class will be tested as part of MachOImageReader. TEST=util_test MachOImageSegmentReader.* R=rsesek@chromium.org Review URL: https://codereview.chromium.org/516983003
This commit is contained in:
parent
af0cfd5a57
commit
1460c47d6a
230
util/mac/mach_o_image_segment_reader.cc
Normal file
230
util/mac/mach_o_image_segment_reader.cc
Normal file
@ -0,0 +1,230 @@
|
||||
// Copyright 2014 The Crashpad Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "util/mac/mach_o_image_segment_reader.h"
|
||||
|
||||
#include <mach-o/loader.h>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "util/mac/checked_mach_address_range.h"
|
||||
#include "util/mac/process_reader.h"
|
||||
#include "util/stdlib/strnlen.h"
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
namespace {
|
||||
|
||||
std::string SizeLimitedCString(const char* c_string, size_t max_length) {
|
||||
return std::string(c_string, strnlen(c_string, max_length));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
MachOImageSegmentReader::MachOImageSegmentReader()
|
||||
: segment_command_(), sections_(), section_map_(), initialized_() {
|
||||
}
|
||||
|
||||
MachOImageSegmentReader::~MachOImageSegmentReader() {
|
||||
}
|
||||
|
||||
bool MachOImageSegmentReader::Initialize(ProcessReader* process_reader,
|
||||
mach_vm_address_t load_command_address,
|
||||
const std::string& load_command_info) {
|
||||
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
|
||||
|
||||
if (!segment_command_.Read(process_reader, load_command_address)) {
|
||||
LOG(WARNING) << "could not read segment_command" << load_command_info;
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint32_t kExpectedSegmentCommand =
|
||||
process_reader->Is64Bit() ? LC_SEGMENT_64 : LC_SEGMENT;
|
||||
DCHECK_EQ(segment_command_.cmd, kExpectedSegmentCommand);
|
||||
DCHECK_GE(segment_command_.cmdsize, segment_command_.Size());
|
||||
const size_t kSectionStructSize =
|
||||
process_types::section::ExpectedSize(process_reader);
|
||||
const size_t kRequiredSize =
|
||||
segment_command_.Size() + segment_command_.nsects * kSectionStructSize;
|
||||
if (segment_command_.cmdsize < kRequiredSize) {
|
||||
LOG(WARNING) << base::StringPrintf(
|
||||
"segment command cmdsize 0x%x insufficient for %u "
|
||||
"section%s (0x%zx)",
|
||||
segment_command_.cmdsize,
|
||||
segment_command_.nsects,
|
||||
segment_command_.nsects == 1 ? "" : "s",
|
||||
kRequiredSize) << load_command_info;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string segment_name = NameInternal();
|
||||
std::string segment_info = base::StringPrintf(
|
||||
", segment %s%s", segment_name.c_str(), load_command_info.c_str());
|
||||
|
||||
// This checks the unslid segment range. The slid range (as loaded into
|
||||
// memory) will be checked later by MachOImageReader.
|
||||
CheckedMachAddressRange segment_range(
|
||||
process_reader, segment_command_.vmaddr, segment_command_.vmsize);
|
||||
if (!segment_range.IsValid()) {
|
||||
LOG(WARNING) << base::StringPrintf("invalid segment range 0x%llx + 0x%llx",
|
||||
segment_command_.vmaddr,
|
||||
segment_command_.vmsize) << segment_info;
|
||||
return false;
|
||||
}
|
||||
|
||||
sections_.resize(segment_command_.nsects);
|
||||
if (!process_types::section::ReadArrayInto(
|
||||
process_reader,
|
||||
load_command_address + segment_command_.Size(),
|
||||
segment_command_.nsects,
|
||||
§ions_[0])) {
|
||||
LOG(WARNING) << "could not read sections" << segment_info;
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t section_index = 0;
|
||||
section_index < sections_.size();
|
||||
++section_index) {
|
||||
const process_types::section& section = sections_[section_index];
|
||||
std::string section_segment_name = SegmentNameString(section.segname);
|
||||
std::string section_name = SectionNameString(section.sectname);
|
||||
std::string section_full_name =
|
||||
SegmentAndSectionNameString(section.segname, section.sectname);
|
||||
|
||||
std::string section_info = base::StringPrintf(", section %s %zu/%zu%s",
|
||||
section_full_name.c_str(),
|
||||
section_index,
|
||||
sections_.size(),
|
||||
load_command_info.c_str());
|
||||
|
||||
if (section_segment_name != segment_name) {
|
||||
LOG(WARNING) << "section.segname incorrect in segment " << segment_name
|
||||
<< section_info;
|
||||
return false;
|
||||
}
|
||||
|
||||
CheckedMachAddressRange section_range(
|
||||
process_reader, section.addr, section.size);
|
||||
if (!section_range.IsValid()) {
|
||||
LOG(WARNING) << base::StringPrintf(
|
||||
"invalid section range 0x%llx + 0x%llx",
|
||||
section.addr,
|
||||
section.size) << section_info;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!segment_range.ContainsRange(section_range)) {
|
||||
LOG(WARNING) << base::StringPrintf(
|
||||
"section at 0x%llx + 0x%llx outside of segment at "
|
||||
"0x%llx + 0x%llx",
|
||||
section.addr,
|
||||
section.size,
|
||||
segment_command_.vmaddr,
|
||||
segment_command_.vmsize) << section_info;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t section_type = (section.flags & SECTION_TYPE);
|
||||
bool zero_fill = section_type == S_ZEROFILL ||
|
||||
section_type == S_GB_ZEROFILL ||
|
||||
section_type == S_THREAD_LOCAL_ZEROFILL;
|
||||
|
||||
// Zero-fill section types aren’t mapped from the file, so their |offset|
|
||||
// fields are irrelevant and are typically 0.
|
||||
if (!zero_fill &&
|
||||
section.offset - segment_command_.fileoff !=
|
||||
section.addr - segment_command_.vmaddr) {
|
||||
LOG(WARNING) << base::StringPrintf(
|
||||
"section type 0x%x at 0x%llx has unexpected offset "
|
||||
"0x%x in segment at 0x%llx with offset 0x%llx",
|
||||
section_type,
|
||||
section.addr,
|
||||
section.offset,
|
||||
segment_command_.vmaddr,
|
||||
segment_command_.fileoff) << section_info;
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& iterator = section_map_.find(section_name);
|
||||
if (iterator != section_map_.end()) {
|
||||
LOG(WARNING) << base::StringPrintf("duplicate section name at %zu",
|
||||
iterator->second) << section_info;
|
||||
return false;
|
||||
}
|
||||
|
||||
section_map_[section_name] = section_index;
|
||||
}
|
||||
|
||||
INITIALIZATION_STATE_SET_VALID(initialized_);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string MachOImageSegmentReader::Name() const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
return NameInternal();
|
||||
}
|
||||
|
||||
const process_types::section* MachOImageSegmentReader::GetSectionByName(
|
||||
const std::string& section_name) const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
|
||||
const auto& iterator = section_map_.find(section_name);
|
||||
if (iterator == section_map_.end()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return §ions_[iterator->second];
|
||||
}
|
||||
|
||||
const process_types::section* MachOImageSegmentReader::GetSectionAtIndex(
|
||||
size_t index) const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
CHECK_LT(index, sections_.size());
|
||||
return §ions_[index];
|
||||
}
|
||||
|
||||
// static
|
||||
std::string MachOImageSegmentReader::SegmentNameString(
|
||||
const char* segment_name_c) {
|
||||
// This is used to interpret the segname field of both the segment_command and
|
||||
// section structures, so be sure that they’re identical.
|
||||
COMPILE_ASSERT(sizeof(process_types::segment_command::segname) ==
|
||||
sizeof(process_types::section::segname),
|
||||
sizes_must_be_equal);
|
||||
|
||||
return SizeLimitedCString(segment_name_c,
|
||||
sizeof(process_types::segment_command::segname));
|
||||
}
|
||||
|
||||
// static
|
||||
std::string MachOImageSegmentReader::SectionNameString(
|
||||
const char* section_name_c) {
|
||||
return SizeLimitedCString(section_name_c,
|
||||
sizeof(process_types::section::sectname));
|
||||
}
|
||||
|
||||
// static
|
||||
std::string MachOImageSegmentReader::SegmentAndSectionNameString(
|
||||
const char* segment_name_c,
|
||||
const char* section_name_c) {
|
||||
return base::StringPrintf("%s,%s",
|
||||
SegmentNameString(segment_name_c).c_str(),
|
||||
SectionNameString(section_name_c).c_str());
|
||||
}
|
||||
|
||||
std::string MachOImageSegmentReader::NameInternal() const {
|
||||
return SegmentNameString(segment_command_.segname);
|
||||
}
|
||||
|
||||
} // namespace crashpad
|
192
util/mac/mach_o_image_segment_reader.h
Normal file
192
util/mac/mach_o_image_segment_reader.h
Normal file
@ -0,0 +1,192 @@
|
||||
// Copyright 2014 The Crashpad Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef CRASHPAD_UTIL_MAC_MACH_O_IMAGE_SEGMENT_READER_H_
|
||||
#define CRASHPAD_UTIL_MAC_MACH_O_IMAGE_SEGMENT_READER_H_
|
||||
|
||||
#include <mach/mach.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "util/mac/process_types.h"
|
||||
#include "util/misc/initialization_state_dcheck.h"
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
class ProcessReader;
|
||||
|
||||
//! \brief A reader for LC_SEGMENT or LC_SEGMENT_64 load commands in Mach-O
|
||||
//! images mapped into another process.
|
||||
//!
|
||||
//! This class is capable of reading both LC_SEGMENT and LC_SEGMENT_64 based on
|
||||
//! the bitness of the remote process.
|
||||
//!
|
||||
//! A MachOImageSegmentReader will normally be instantiated by a
|
||||
//! MachOImageReader.
|
||||
class MachOImageSegmentReader {
|
||||
public:
|
||||
MachOImageSegmentReader();
|
||||
~MachOImageSegmentReader();
|
||||
|
||||
//! \brief Reads the segment load command from another process.
|
||||
//!
|
||||
//! This method must only be called once on an object. This method must be
|
||||
//! called successfully before any other method in this class may be called.
|
||||
//!
|
||||
//! \param[in] process_reader The reader for the remote process.
|
||||
//! \param[in] load_command_address The address, in the remote process’
|
||||
//! address space, where the LC_SEGMENT or LC_SEGMENT_64 load command
|
||||
//! to be read is located. This address is determined by a Mach-O image
|
||||
//! reader, such as MachOImageReader, as it walks Mach-O load commands.
|
||||
//! \param[in] load_command_info A string to be used in logged messages. This
|
||||
//! string is for diagnostic purposes only, and may be empty.
|
||||
//!
|
||||
//! \return `true` if the load command was read successfully. `false`
|
||||
//! otherwise, with an appropriate message logged.
|
||||
bool Initialize(ProcessReader* process_reader,
|
||||
mach_vm_address_t load_command_address,
|
||||
const std::string& load_command_info);
|
||||
|
||||
//! \brief Returns the segment’s name.
|
||||
//!
|
||||
//! The segment’s name is taken from the load command’s `segname` field.
|
||||
//! Common segment names are `"__TEXT"`, `"__DATA"`, and `"__LINKEDIT"`.
|
||||
//! Symbolic constants for these common names are defined in
|
||||
//! `<mach-o/loader.h>`.
|
||||
std::string Name() const;
|
||||
|
||||
//! \brief The segment’s preferred load address.
|
||||
//!
|
||||
//! \return The segment’s preferred load address as stored in the Mach-O file.
|
||||
//!
|
||||
//! \note This value is not adjusted for any “slide” that may have occurred
|
||||
//! when the image was loaded.
|
||||
//!
|
||||
//! \sa MachOImageReader::GetSegmentByName()
|
||||
mach_vm_address_t vmaddr() const { return segment_command_.vmaddr; }
|
||||
|
||||
//! \brief Returns the segment’s size as mapped into memory.
|
||||
mach_vm_size_t vmsize() const { return segment_command_.vmsize; }
|
||||
|
||||
//! \brief Returns the file offset of the mapped segment in the file from
|
||||
//! which it was mapped.
|
||||
//!
|
||||
//! The file offset is the difference between the beginning of the
|
||||
//! `mach_header` or `mach_header_64` and the beginning of the segment’s
|
||||
//! mapped region. For segments that are not mapped from a file (such as
|
||||
//! `"__PAGEZERO"` segments), this will be `0`.
|
||||
mach_vm_size_t fileoff() const { return segment_command_.fileoff; }
|
||||
|
||||
//! \brief Returns the number of sections in the segment.
|
||||
//!
|
||||
//! This will return `0` for a segment without any sections, typical for
|
||||
//! `"__PAGEZERO"` and `"__LINKEDIT"` segments.
|
||||
//!
|
||||
//! Although the Mach-O file format uses a `uint32_t` for this field, there is
|
||||
//! an overall limit of 255 sections in an entire Mach-O image file (not just
|
||||
//! in a single segment) imposed by the symbol table format. Symbols will not
|
||||
//! be able to reference anything in a section beyond the first 255 in a
|
||||
//! Mach-O image file.
|
||||
uint32_t nsects() const { return segment_command_.nsects; }
|
||||
|
||||
//! \brief Obtain section information by section name.
|
||||
//!
|
||||
//! \param[in] section_name The name of the section to search for, without the
|
||||
//! leading segment name. For example, use `"__text"`, not
|
||||
//! `"__TEXT,__text"` or `"__TEXT.__text"`.
|
||||
//!
|
||||
//! \return A pointer to the section information if it was found, or `NULL` if
|
||||
//! it was not found.
|
||||
//!
|
||||
//! \note The process_types::section::addr field gives the section’s preferred
|
||||
//! load address as stored in the Mach-O image file, and is not adjusted
|
||||
//! for any “slide” that may have occurred when the image was loaded.
|
||||
//!
|
||||
//! \sa MachOImageReader::GetSectionByName()
|
||||
const process_types::section* GetSectionByName(
|
||||
const std::string& section_name) const;
|
||||
|
||||
//! \brief Obtain section information by section index.
|
||||
//!
|
||||
//! \param[in] index The index of the section to return, in the order that it
|
||||
//! appears in the segment load command. Unlike
|
||||
//! MachOImageReader::GetSectionAtIndex(), this is a 0-based index. This
|
||||
//! parameter must be in the range of valid indices aas reported by
|
||||
//! nsects().
|
||||
//!
|
||||
//! \return A pointer to the section information. If \a index is out of range,
|
||||
//! execution is aborted.
|
||||
//!
|
||||
//! \note The process_types::section::addr field gives the section’s preferred
|
||||
//! load address as stored in the Mach-O image file, and is not adjusted
|
||||
//! for any “slide” that may have occurred when the image was loaded.
|
||||
//!
|
||||
//! \sa MachOImageReader::GetSectionAtIndex()
|
||||
const process_types::section* GetSectionAtIndex(size_t index) const;
|
||||
|
||||
//! \brief Returns a segment name string.
|
||||
//!
|
||||
//! Segment names may be 16 characters long, and are not necessarily
|
||||
//! `NUL`-terminated. This function will return a segment name based on up to
|
||||
//! the first 16 characters found at \a segment_name_c.
|
||||
static std::string SegmentNameString(const char* segment_name_c);
|
||||
|
||||
//! \brief Returns a section name string.
|
||||
//!
|
||||
//! Section names may be 16 characters long, and are not necessarily
|
||||
//! `NUL`-terminated. This function will return a section name based on up to
|
||||
//! the first 16 characters found at \a section_name_c.
|
||||
static std::string SectionNameString(const char* section_name_c);
|
||||
|
||||
//! \brief Returns a segment and section name string.
|
||||
//!
|
||||
//! A segment and section name string is composed of a segment name string
|
||||
//! (see SegmentNameString()) and a section name string (see
|
||||
//! SectionNameString()) separated by a comma. An example is
|
||||
//! `"__TEXT,__text"`.
|
||||
static std::string SegmentAndSectionNameString(const char* segment_name_c,
|
||||
const char* section_name_c);
|
||||
|
||||
private:
|
||||
//! \brief The internal implementation of Name().
|
||||
//!
|
||||
//! This is identical to Name() but does not perform the
|
||||
//! InitializationStateDcheck check. It may be called during initialization
|
||||
//! provided that the caller only does so after segment_command_ has been
|
||||
//! read successfully.
|
||||
std::string NameInternal() const;
|
||||
|
||||
// The segment command data read from the remote process.
|
||||
process_types::segment_command segment_command_;
|
||||
|
||||
// Section structures read from the remote process in the order that they are
|
||||
// given in the remote process.
|
||||
std::vector<process_types::section> sections_;
|
||||
|
||||
// Maps section names to indices into the sections_ vector.
|
||||
std::map<std::string, size_t> section_map_;
|
||||
|
||||
InitializationStateDcheck initialized_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(MachOImageSegmentReader);
|
||||
};
|
||||
|
||||
} // namespace crashpad
|
||||
|
||||
#endif // CRASHPAD_UTIL_MAC_MACH_O_IMAGE_SEGMENT_READER_H_
|
186
util/mac/mach_o_image_segment_reader_test.cc
Normal file
186
util/mac/mach_o_image_segment_reader_test.cc
Normal file
@ -0,0 +1,186 @@
|
||||
// Copyright 2014 The Crashpad Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "util/mac/mach_o_image_segment_reader.h"
|
||||
|
||||
#include <mach-o/loader.h>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace crashpad;
|
||||
|
||||
// Most of MachOImageSegmentReader is tested as part of MachOImageReader, which
|
||||
// depends on MachOImageSegmentReader to provide major portions of its
|
||||
// functionality. Because MachOImageSegmentReader is difficult to use except by
|
||||
// a Mach-O load command reader such as MachOImageReader, these portions
|
||||
// of MachOImageSegmentReader are not tested independently.
|
||||
//
|
||||
// The tests here exercise the portions of MachOImageSegmentReader that are
|
||||
// exposed and independently useful.
|
||||
|
||||
TEST(MachOImageSegmentReader, SegmentNameString) {
|
||||
// The output value should be a string of up to 16 characters, even if the
|
||||
// input value is not NUL-terminated within 16 characters.
|
||||
EXPECT_EQ("__TEXT", MachOImageSegmentReader::SegmentNameString("__TEXT"));
|
||||
EXPECT_EQ("__OVER", MachOImageSegmentReader::SegmentNameString("__OVER"));
|
||||
EXPECT_EQ("", MachOImageSegmentReader::SegmentNameString(""));
|
||||
EXPECT_EQ("p", MachOImageSegmentReader::SegmentNameString("p"));
|
||||
EXPECT_EQ("NoUnderChar",
|
||||
MachOImageSegmentReader::SegmentNameString("NoUnderChar"));
|
||||
EXPECT_EQ("0123456789abcde",
|
||||
MachOImageSegmentReader::SegmentNameString("0123456789abcde"));
|
||||
EXPECT_EQ("0123456789abcdef",
|
||||
MachOImageSegmentReader::SegmentNameString("0123456789abcdef"));
|
||||
EXPECT_EQ("gfedcba987654321",
|
||||
MachOImageSegmentReader::SegmentNameString("gfedcba9876543210"));
|
||||
EXPECT_EQ("hgfedcba98765432",
|
||||
MachOImageSegmentReader::SegmentNameString("hgfedcba9876543210"));
|
||||
|
||||
// Segment names defined in <mach-o/loader.h>. All of these should come
|
||||
// through SegmentNameString() cleanly and without truncation.
|
||||
const char* kSegmentTestData[] = {
|
||||
SEG_TEXT,
|
||||
SEG_DATA,
|
||||
SEG_OBJC,
|
||||
SEG_ICON,
|
||||
SEG_LINKEDIT,
|
||||
SEG_UNIXSTACK,
|
||||
SEG_IMPORT,
|
||||
};
|
||||
|
||||
for (size_t index = 0; index < arraysize(kSegmentTestData); ++index) {
|
||||
EXPECT_EQ(
|
||||
kSegmentTestData[index],
|
||||
MachOImageSegmentReader::SegmentNameString(kSegmentTestData[index]))
|
||||
<< base::StringPrintf("index %zu", index);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(MachOImageSegmentReader, SectionNameString) {
|
||||
// The output value should be a string of up to 16 characters, even if the
|
||||
// input value is not NUL-terminated within 16 characters.
|
||||
EXPECT_EQ("__text", MachOImageSegmentReader::SectionNameString("__text"));
|
||||
EXPECT_EQ("__over", MachOImageSegmentReader::SectionNameString("__over"));
|
||||
EXPECT_EQ("", MachOImageSegmentReader::SectionNameString(""));
|
||||
EXPECT_EQ("p", MachOImageSegmentReader::SectionNameString("p"));
|
||||
EXPECT_EQ("NoUnderChar",
|
||||
MachOImageSegmentReader::SectionNameString("NoUnderChar"));
|
||||
EXPECT_EQ("0123456789abcde",
|
||||
MachOImageSegmentReader::SectionNameString("0123456789abcde"));
|
||||
EXPECT_EQ("0123456789abcdef",
|
||||
MachOImageSegmentReader::SectionNameString("0123456789abcdef"));
|
||||
EXPECT_EQ("gfedcba987654321",
|
||||
MachOImageSegmentReader::SectionNameString("gfedcba9876543210"));
|
||||
EXPECT_EQ("hgfedcba98765432",
|
||||
MachOImageSegmentReader::SectionNameString("hgfedcba9876543210"));
|
||||
|
||||
// Section names defined in <mach-o/loader.h>. All of these should come
|
||||
// through SectionNameString() cleanly and without truncation.
|
||||
const char* kSectionTestData[] = {
|
||||
SECT_TEXT,
|
||||
SECT_FVMLIB_INIT0,
|
||||
SECT_FVMLIB_INIT1,
|
||||
SECT_DATA,
|
||||
SECT_BSS,
|
||||
SECT_COMMON,
|
||||
SECT_OBJC_SYMBOLS,
|
||||
SECT_OBJC_MODULES,
|
||||
SECT_OBJC_STRINGS,
|
||||
SECT_OBJC_REFS,
|
||||
SECT_ICON_HEADER,
|
||||
SECT_ICON_TIFF,
|
||||
};
|
||||
|
||||
for (size_t index = 0; index < arraysize(kSectionTestData); ++index) {
|
||||
EXPECT_EQ(
|
||||
kSectionTestData[index],
|
||||
MachOImageSegmentReader::SectionNameString(kSectionTestData[index]))
|
||||
<< base::StringPrintf("index %zu", index);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(MachOImageSegmentReader, SegmentAndSectionNameString) {
|
||||
struct SegmentAndSectionTestData {
|
||||
const char* segment;
|
||||
const char* section;
|
||||
const char* output;
|
||||
};
|
||||
const SegmentAndSectionTestData kSegmentAndSectionTestData[] = {
|
||||
{"segment", "section", "segment,section"},
|
||||
{"Segment", "Section", "Segment,Section"},
|
||||
{"SEGMENT", "SECTION", "SEGMENT,SECTION"},
|
||||
{"__TEXT", "__plain", "__TEXT,__plain"},
|
||||
{"__TEXT", "poetry", "__TEXT,poetry"},
|
||||
{"__TEXT", "Prose", "__TEXT,Prose"},
|
||||
{"__PLAIN", "__text", "__PLAIN,__text"},
|
||||
{"rich", "__text", "rich,__text"},
|
||||
{"segment", "", "segment,"},
|
||||
{"", "section", ",section"},
|
||||
{"", "", ","},
|
||||
{"0123456789abcdef", "section", "0123456789abcdef,section"},
|
||||
{"gfedcba9876543210", "section", "gfedcba987654321,section"},
|
||||
{"0123456789abcdef", "", "0123456789abcdef,"},
|
||||
{"gfedcba9876543210", "", "gfedcba987654321,"},
|
||||
{"segment", "0123456789abcdef", "segment,0123456789abcdef"},
|
||||
{"segment", "gfedcba9876543210", "segment,gfedcba987654321"},
|
||||
{"", "0123456789abcdef", ",0123456789abcdef"},
|
||||
{"", "gfedcba9876543210", ",gfedcba987654321"},
|
||||
{"0123456789abcdef",
|
||||
"0123456789abcdef",
|
||||
"0123456789abcdef,0123456789abcdef"},
|
||||
{"gfedcba9876543210",
|
||||
"gfedcba9876543210",
|
||||
"gfedcba987654321,gfedcba987654321"},
|
||||
|
||||
// Sections defined in <mach-o/loader.h>. All of these should come through
|
||||
// SegmentAndSectionNameString() cleanly and without truncation.
|
||||
{SEG_TEXT, SECT_TEXT, "__TEXT,__text"},
|
||||
{SEG_TEXT, SECT_FVMLIB_INIT0, "__TEXT,__fvmlib_init0"},
|
||||
{SEG_TEXT, SECT_FVMLIB_INIT1, "__TEXT,__fvmlib_init1"},
|
||||
{SEG_DATA, SECT_DATA, "__DATA,__data"},
|
||||
{SEG_DATA, SECT_BSS, "__DATA,__bss"},
|
||||
{SEG_DATA, SECT_COMMON, "__DATA,__common"},
|
||||
{SEG_OBJC, SECT_OBJC_SYMBOLS, "__OBJC,__symbol_table"},
|
||||
{SEG_OBJC, SECT_OBJC_MODULES, "__OBJC,__module_info"},
|
||||
{SEG_OBJC, SECT_OBJC_STRINGS, "__OBJC,__selector_strs"},
|
||||
{SEG_OBJC, SECT_OBJC_REFS, "__OBJC,__selector_refs"},
|
||||
{SEG_ICON, SECT_ICON_HEADER, "__ICON,__header"},
|
||||
{SEG_ICON, SECT_ICON_TIFF, "__ICON,__tiff"},
|
||||
|
||||
// These segments don’t normally have sections, but the above group tested
|
||||
// the known segment names for segments that do normally have sections.
|
||||
// This group does the same for segments that normally don’t.
|
||||
{SEG_LINKEDIT, "", "__LINKEDIT,"},
|
||||
{SEG_UNIXSTACK, "", "__UNIXSTACK,"},
|
||||
{SEG_IMPORT, "", "__IMPORT,"},
|
||||
};
|
||||
|
||||
for (size_t index = 0; index < arraysize(kSegmentAndSectionTestData);
|
||||
++index) {
|
||||
const SegmentAndSectionTestData& test = kSegmentAndSectionTestData[index];
|
||||
EXPECT_EQ(test.output,
|
||||
MachOImageSegmentReader::SegmentAndSectionNameString(
|
||||
test.segment, test.section))
|
||||
<< base::StringPrintf("index %zu, segment %s, section %s",
|
||||
index,
|
||||
test.segment,
|
||||
test.section);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
@ -38,6 +38,8 @@
|
||||
'mac/launchd.mm',
|
||||
'mac/mac_util.cc',
|
||||
'mac/mac_util.h',
|
||||
'mac/mach_o_image_segment_reader.cc',
|
||||
'mac/mach_o_image_segment_reader.h',
|
||||
'mac/service_management.cc',
|
||||
'mac/service_management.h',
|
||||
'mac/process_reader.cc',
|
||||
@ -125,6 +127,7 @@
|
||||
'mac/checked_mach_address_range_test.cc',
|
||||
'mac/launchd_test.mm',
|
||||
'mac/mac_util_test.mm',
|
||||
'mac/mach_o_image_segment_reader_test.cc',
|
||||
'mac/process_reader_test.cc',
|
||||
'mac/process_types_test.cc',
|
||||
'mac/service_management_test.mm',
|
||||
|
Loading…
x
Reference in New Issue
Block a user