OLD | NEW |
---|---|
(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 §ions_[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 §ions_[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 §ions_[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 | |
OLD | NEW |