Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(597)

Side by Side Diff: util/mac/mach_o_image_segment_reader.cc

Issue 516983003: Add MachOImageSegmentReader (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2014 The Crashpad Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "util/mac/mach_o_image_segment_reader.h"
16
17 #include <mach-o/loader.h>
18
19 #include "base/logging.h"
20 #include "base/strings/stringprintf.h"
21 #include "util/mac/checked_mach_address_range.h"
22 #include "util/mac/process_reader.h"
23 #include "util/stdlib/strnlen.h"
24
25 namespace crashpad {
26
27 namespace {
28
29 std::string SizeLimitedCString(const char* c_string, size_t max_length) {
30 return std::string(c_string, strnlen(c_string, max_length));
31 }
32
33 } // namespace
34
35 MachOImageSegmentReader::MachOImageSegmentReader()
36 : segment_command_(), sections_(), section_map_(), initialized_() {
37 }
38
39 MachOImageSegmentReader::~MachOImageSegmentReader() {
40 }
41
42 bool MachOImageSegmentReader::Initialize(ProcessReader* process_reader,
43 mach_vm_address_t load_command_address,
44 const std::string& load_command_info) {
45 INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
46
47 if (!segment_command_.Read(process_reader, load_command_address)) {
48 LOG(WARNING) << "could not read segment_command" << load_command_info;
49 return false;
50 }
51
52 const uint32_t kExpectedSegmentCommand =
53 process_reader->Is64Bit() ? LC_SEGMENT_64 : LC_SEGMENT;
54 DCHECK_EQ(segment_command_.cmd, kExpectedSegmentCommand);
55 DCHECK_GE(segment_command_.cmdsize, segment_command_.Size());
56 const size_t kSectionStructSize =
57 process_types::section::ExpectedSize(process_reader);
58 const size_t kRequiredSize =
59 segment_command_.Size() + segment_command_.nsects * kSectionStructSize;
60 if (segment_command_.cmdsize < kRequiredSize) {
61 LOG(WARNING) << base::StringPrintf(
62 "segment command cmdsize 0x%x insufficient for %u "
63 "section%s (0x%zx)",
64 segment_command_.cmdsize,
65 segment_command_.nsects,
66 segment_command_.nsects == 1 ? "" : "s",
67 kRequiredSize) << load_command_info;
68 return false;
69 }
70
71 std::string segment_name = NameInternal();
72 std::string segment_info = base::StringPrintf(
73 ", segment %s%s", segment_name.c_str(), load_command_info.c_str());
74
75 // This checks the unslid segment range. The slid range (as loaded into
76 // memory) will be checked later by MachOImageReader.
77 CheckedMachAddressRange segment_range(
78 process_reader, segment_command_.vmaddr, segment_command_.vmsize);
79 if (!segment_range.IsValid()) {
80 LOG(WARNING) << base::StringPrintf("invalid segment range 0x%llx + 0x%llx",
81 segment_command_.vmaddr,
82 segment_command_.vmsize) << segment_info;
83 return false;
84 }
85
86 sections_.resize(segment_command_.nsects);
87 if (!process_types::section::ReadArrayInto(
88 process_reader,
89 load_command_address + segment_command_.Size(),
90 segment_command_.nsects,
91 &sections_[0])) {
92 LOG(WARNING) << "could not read sections" << segment_info;
93 return false;
94 }
95
96 for (size_t section_index = 0;
97 section_index < sections_.size();
98 ++section_index) {
99 const process_types::section& section = sections_[section_index];
100 std::string section_segment_name = SegmentNameString(section.segname);
101 std::string section_name = SectionNameString(section.sectname);
102 std::string section_full_name =
103 SegmentAndSectionNameString(section.segname, section.sectname);
104
105 std::string section_info = base::StringPrintf(", section %s %zu/%zu%s",
106 section_full_name.c_str(),
107 section_index,
108 sections_.size(),
109 load_command_info.c_str());
110
111 if (section_segment_name != segment_name) {
112 LOG(WARNING) << "section.segname incorrect in segment " << segment_name
113 << section_info;
114 return false;
115 }
116
117 CheckedMachAddressRange section_range(
118 process_reader, section.addr, section.size);
119 if (!section_range.IsValid()) {
120 LOG(WARNING) << base::StringPrintf(
121 "invalid section range 0x%llx + 0x%llx",
122 section.addr,
123 section.size) << section_info;
124 return false;
125 }
126
127 if (!segment_range.ContainsRange(section_range)) {
128 LOG(WARNING) << base::StringPrintf(
129 "section at 0x%llx + 0x%llx outside of segment at "
130 "0x%llx + 0x%llx",
131 section.addr,
132 section.size,
133 segment_command_.vmaddr,
134 segment_command_.vmsize) << section_info;
135 return false;
136 }
137
138 uint32_t section_type = (section.flags & SECTION_TYPE);
139 bool zero_fill = section_type == S_ZEROFILL ||
140 section_type == S_GB_ZEROFILL ||
141 section_type == S_THREAD_LOCAL_ZEROFILL;
142
143 // Zero-fill section types aren’t mapped from the file, so their |offset|
144 // fields are irrelevant and are typically 0.
145 if (!zero_fill &&
146 section.offset - segment_command_.fileoff !=
147 section.addr - segment_command_.vmaddr) {
148 LOG(WARNING) << base::StringPrintf(
149 "section type 0x%x at 0x%llx has unexpected offset "
150 "0x%x in segment at 0x%llx with offset 0x%llx",
151 section_type,
152 section.addr,
153 section.offset,
154 segment_command_.vmaddr,
155 segment_command_.fileoff) << section_info;
156 return false;
157 }
158
159 const auto& iterator = section_map_.find(section_name);
160 if (iterator != section_map_.end()) {
161 LOG(WARNING) << base::StringPrintf("duplicate section name at %zu",
162 iterator->second) << section_info;
163 return false;
164 }
165
166 section_map_[section_name] = section_index;
167 }
168
169 INITIALIZATION_STATE_SET_VALID(initialized_);
170 return true;
171 }
172
173 std::string MachOImageSegmentReader::Name() const {
174 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
175 return NameInternal();
176 }
177
178 const process_types::section* MachOImageSegmentReader::GetSectionByName(
179 const std::string& section_name) const {
180 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
181
182 const auto& iterator = section_map_.find(section_name);
183 if (iterator == section_map_.end()) {
184 return NULL;
185 }
186
187 return &sections_[iterator->second];
188 }
189
190 const process_types::section* MachOImageSegmentReader::GetSectionAtIndex(
191 size_t index) const {
192 INITIALIZATION_STATE_DCHECK_VALID(initialized_);
193 CHECK(index < sections_.size());
Robert Sesek 2014/09/02 16:40:09 CHECK_LT?
194 return &sections_[index];
195 }
196
197 // static
198 std::string MachOImageSegmentReader::SegmentNameString(
199 const char* segment_name_c) {
200 // This is used to interpret the segname field of both the segment_command and
201 // section structures, so be sure that they’re identical.
202 COMPILE_ASSERT(sizeof(process_types::segment_command::segname) ==
203 sizeof(process_types::section::segname),
204 sizes_must_be_equal);
205
206 return SizeLimitedCString(segment_name_c,
207 sizeof(process_types::segment_command::segname));
208 }
209
210 // static
211 std::string MachOImageSegmentReader::SectionNameString(
212 const char* section_name_c) {
213 return SizeLimitedCString(section_name_c,
214 sizeof(process_types::section::sectname));
215 }
216
217 // static
218 std::string MachOImageSegmentReader::SegmentAndSectionNameString(
219 const char* segment_name_c,
220 const char* section_name_c) {
221 return base::StringPrintf("%s,%s",
222 SegmentNameString(segment_name_c).c_str(),
223 SectionNameString(section_name_c).c_str());
224 }
225
226 std::string MachOImageSegmentReader::NameInternal() const {
227 return SegmentNameString(segment_command_.segname);
228 }
229
230 } // namespace crashpad
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698