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_annotations_reader.h" | |
16 | |
17 #include <mach-o/loader.h> | |
18 #include <mach/mach.h> | |
19 | |
20 #include "base/logging.h" | |
21 #include "util/mac/mach_o_image_reader.h" | |
22 #include "util/mac/process_reader.h" | |
23 #include "util/mac/process_types.h" | |
24 #include "util/mach/task_memory.h" | |
25 #include "util/stdlib/strnlen.h" | |
26 | |
27 namespace crashpad { | |
28 | |
29 MachOImageAnnotationsReader::MachOImageAnnotationsReader( | |
30 ProcessReader* process_reader, | |
31 const MachOImageReader* image_reader, | |
32 const std::string& name) | |
33 : name_(name), | |
34 process_reader_(process_reader), | |
35 image_reader_(image_reader) { | |
36 } | |
37 | |
38 std::vector<std::string> MachOImageAnnotationsReader::Vector() const { | |
39 std::vector<std::string> vector_annotations; | |
40 | |
41 ReadCrashReporterClientAnnotations(&vector_annotations); | |
42 ReadDyldErrorStringAnnotation(&vector_annotations); | |
43 | |
44 return vector_annotations; | |
45 } | |
46 | |
47 std::map<std::string, std::string> MachOImageAnnotationsReader::SimpleMap() | |
48 const { | |
49 std::map<std::string, std::string> simple_map_annotations; | |
50 | |
51 ReadCrashpadSimpleAnnotations(&simple_map_annotations); | |
52 | |
53 return simple_map_annotations; | |
54 } | |
55 | |
56 void MachOImageAnnotationsReader::ReadCrashReporterClientAnnotations( | |
57 std::vector<std::string>* vector_annotations) const { | |
58 mach_vm_address_t crash_info_address; | |
59 const process_types::section* crash_info_section = | |
60 image_reader_->GetSectionByName( | |
61 SEG_DATA, "__crash_info", &crash_info_address); | |
62 if (!crash_info_section) { | |
63 return; | |
64 } | |
65 | |
66 process_types::crashreporter_annotations_t crash_info; | |
67 if (crash_info_section->size < crash_info.ExpectedSize(process_reader_)) { | |
68 LOG(WARNING) << "small crash info section size " << crash_info_section->size | |
69 << " in " << name_; | |
70 return; | |
71 } | |
72 | |
73 if (!crash_info.Read(process_reader_, crash_info_address)) { | |
74 LOG(WARNING) << "could not read crash info from " << name_; | |
75 return; | |
76 } | |
77 | |
78 if (crash_info.version != 4) { | |
79 LOG(WARNING) << "unexpected crash info version " << crash_info.version | |
80 << " in " << name_; | |
81 return; | |
82 } | |
83 | |
84 // This number was totally made up out of nowhere, but it seems prudent to | |
85 // enforce some limit. | |
86 const size_t kMaxMessageSize = 1024; | |
87 if (crash_info.message) { | |
88 std::string message; | |
89 if (process_reader_->Memory() | |
90 ->ReadCStringSizeLimited( | |
Robert Sesek
2014/10/15 20:25:20
nit: break after ( instead of -> ?
| |
91 crash_info.message, kMaxMessageSize, &message)) { | |
92 vector_annotations->push_back(message); | |
93 } else { | |
94 LOG(WARNING) << "could not read crash message in " << name_; | |
95 } | |
96 } | |
97 | |
98 if (crash_info.message2) { | |
99 std::string message; | |
100 if (process_reader_->Memory() | |
101 ->ReadCStringSizeLimited( | |
102 crash_info.message2, kMaxMessageSize, &message)) { | |
103 vector_annotations->push_back(message); | |
104 } else { | |
105 LOG(WARNING) << "could not read crash message 2 in " << name_; | |
106 } | |
107 } | |
108 } | |
109 | |
110 void MachOImageAnnotationsReader::ReadDyldErrorStringAnnotation( | |
111 std::vector<std::string>* vector_annotations) const { | |
112 // dyld stores its error string at the external symbol for |const char | |
113 // error_string[1024]|. See 10.9.5 dyld-239.4/src/dyld.cpp error_string. | |
114 if (image_reader_->FileType() != MH_DYLINKER) { | |
115 return; | |
116 } | |
117 | |
118 mach_vm_address_t error_string_address; | |
119 if (!image_reader_->LookUpExternalDefinedSymbol("_error_string", | |
120 &error_string_address)) { | |
121 return; | |
122 } | |
123 | |
124 std::string message; | |
125 if (process_reader_->Memory() | |
126 ->ReadCStringSizeLimited(error_string_address, 1024, &message)) { | |
Robert Sesek
2014/10/15 20:25:20
Globalize and use the kMaxMessageSize from above.
Mark Mentovai
2014/10/15 21:20:21
Robert Sesek wrote:
| |
127 if (!message.empty()) { | |
128 vector_annotations->push_back(message); | |
129 } | |
130 } else { | |
131 LOG(WARNING) << "could not read dylinker error string from " << name_; | |
132 } | |
133 } | |
134 | |
135 void MachOImageAnnotationsReader::ReadCrashpadSimpleAnnotations( | |
136 std::map<std::string, std::string>* simple_map_annotations) const { | |
137 mach_vm_address_t crashpad_info_address; | |
138 const process_types::section* crashpad_info_section = | |
139 image_reader_->GetSectionByName( | |
140 SEG_DATA, "__crashpad_info", &crashpad_info_address); | |
141 if (!crashpad_info_section) { | |
142 return; | |
143 } | |
144 | |
145 process_types::CrashpadInfo crashpad_info; | |
146 if (crashpad_info_section->size < | |
147 crashpad_info.ExpectedSize(process_reader_)) { | |
148 LOG(WARNING) << "small crashpad info section size " | |
149 << crashpad_info_section->size << " in " << name_; | |
150 return; | |
151 } | |
152 | |
153 if (!crashpad_info.Read(process_reader_, crashpad_info_address)) { | |
154 LOG(WARNING) << "could not read crashpad info from " << name_; | |
155 return; | |
156 } | |
157 | |
158 if (crashpad_info.signature != 'cpad' || | |
159 crashpad_info.size != crashpad_info_section->size || | |
160 crashpad_info.version < 1) { | |
161 LOG(WARNING) << "unexpected crashpad info data in " << name_; | |
162 return; | |
163 } | |
164 | |
165 if (!crashpad_info.simple_annotations) { | |
166 return; | |
167 } | |
168 | |
169 struct Entry { | |
Robert Sesek
2014/10/15 20:25:20
Why not use SimpleStringDictionary::Entry here?
Mark Mentovai
2014/10/15 21:20:21
Robert Sesek wrote:
| |
170 char key[256]; | |
171 char value[256]; | |
172 }; | |
173 const size_t kNumEntries = 64; | |
Robert Sesek
2014/10/15 20:25:20
Similarly, SimpleStringDictionary::num_entries.
| |
174 std::vector<Entry> simple_annotations(kNumEntries); | |
175 if (!process_reader_->Memory() | |
176 ->Read(crashpad_info.simple_annotations, | |
177 sizeof(Entry) * kNumEntries, | |
178 &simple_annotations[0])) { | |
179 LOG(WARNING) << "could not read simple annotations from " << name_; | |
180 return; | |
181 } | |
182 | |
183 for (const auto& entry : simple_annotations) { | |
184 size_t key_length = strnlen(entry.key, sizeof(entry.key)); | |
185 if (key_length) { | |
186 std::string key(entry.key, key_length); | |
187 std::string value(entry.value, strnlen(entry.value, sizeof(entry.value))); | |
188 if (!simple_map_annotations->count(key)) { | |
189 simple_map_annotations->insert( | |
190 std::pair<std::string, std::string>(key, value)); | |
191 } else { | |
192 LOG(INFO) << "duplicate simple annotation " << key << " in " << name_; | |
193 } | |
194 } | |
195 } | |
196 } | |
197 | |
198 } // namespace crashpad | |
OLD | NEW |