OLD | NEW |
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/profiler/native_stack_sampler.h" | 5 #include "base/profiler/native_stack_sampler.h" |
6 | 6 |
7 #include <dlfcn.h> | 7 #include <dlfcn.h> |
8 #include <libkern/OSByteOrder.h> | 8 #include <libkern/OSByteOrder.h> |
9 #include <libunwind.h> | 9 #include <libunwind.h> |
10 #include <mach-o/swap.h> | 10 #include <mach-o/swap.h> |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
157 } | 157 } |
158 | 158 |
159 const char* LibSystemKernelName() { | 159 const char* LibSystemKernelName() { |
160 static char path[PATH_MAX]; | 160 static char path[PATH_MAX]; |
161 static char* name = nullptr; | 161 static char* name = nullptr; |
162 if (name) | 162 if (name) |
163 return name; | 163 return name; |
164 | 164 |
165 Dl_info info; | 165 Dl_info info; |
166 dladdr(reinterpret_cast<void*>(_exit), &info); | 166 dladdr(reinterpret_cast<void*>(_exit), &info); |
167 strncpy(path, info.dli_fname, PATH_MAX); | 167 strlcpy(path, info.dli_fname, PATH_MAX); |
168 name = path; | 168 name = path; |
169 | 169 |
170 #if !defined(ADDRESS_SANITIZER) | 170 #if !defined(ADDRESS_SANITIZER) |
171 DCHECK_EQ(std::string(name), | 171 DCHECK_EQ(std::string(name), |
172 std::string("/usr/lib/system/libsystem_kernel.dylib")); | 172 std::string("/usr/lib/system/libsystem_kernel.dylib")); |
173 #endif | 173 #endif |
174 return name; | 174 return name; |
175 } | 175 } |
176 | 176 |
177 // Walks the stack represented by |thread_state|, calling back to the provided | 177 // Walks the stack represented by |thread_state|, calling back to the provided |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
215 strcmp(info.dli_fname, LibSystemKernelName()) == 0) { | 215 strcmp(info.dli_fname, LibSystemKernelName()) == 0) { |
216 rip = *reinterpret_cast<uint64_t*>(rsp); | 216 rip = *reinterpret_cast<uint64_t*>(rsp); |
217 rsp += 8; | 217 rsp += 8; |
218 WalkStackFromContext(&unwind_context, &frame_count, callback); | 218 WalkStackFromContext(&unwind_context, &frame_count, callback); |
219 } | 219 } |
220 } | 220 } |
221 } | 221 } |
222 | 222 |
223 // Module identifiers --------------------------------------------------------- | 223 // Module identifiers --------------------------------------------------------- |
224 | 224 |
225 // Returns the hex encoding of a 16-byte ID for the binary loaded at | 225 // Returns the unique build ID for a module loaded at |module_addr|. Returns the |
226 // |module_addr|. Returns an empty string if the UUID cannot be found at | 226 // empty string if the function fails to get the build ID. |
227 // |module_addr|. | 227 // |
| 228 // Build IDs are created by the concatenation of the module's GUID (Windows) / |
| 229 // UUID (Mac) and an "age" field that indicates how many times that GUID/UUID |
| 230 // has been reused. In Windows binaries, the "age" field is present in the |
| 231 // module header, but on the Mac, UUIDs are never reused and so the "age" value |
| 232 // appended to the UUID is always 0. |
228 std::string GetUniqueId(const void* module_addr) { | 233 std::string GetUniqueId(const void* module_addr) { |
229 const mach_header_64* mach_header = | 234 const mach_header_64* mach_header = |
230 reinterpret_cast<const mach_header_64*>(module_addr); | 235 reinterpret_cast<const mach_header_64*>(module_addr); |
231 DCHECK_EQ(MH_MAGIC_64, mach_header->magic); | 236 DCHECK_EQ(MH_MAGIC_64, mach_header->magic); |
232 | 237 |
233 size_t offset = sizeof(mach_header_64); | 238 size_t offset = sizeof(mach_header_64); |
234 size_t offset_limit = sizeof(mach_header_64) + mach_header->sizeofcmds; | 239 size_t offset_limit = sizeof(mach_header_64) + mach_header->sizeofcmds; |
235 for (uint32_t i = 0; (i < mach_header->ncmds) && | 240 for (uint32_t i = 0; (i < mach_header->ncmds) && |
236 (offset + sizeof(load_command) < offset_limit); | 241 (offset + sizeof(load_command) < offset_limit); |
237 ++i) { | 242 ++i) { |
238 const load_command* current_cmd = reinterpret_cast<const load_command*>( | 243 const load_command* current_cmd = reinterpret_cast<const load_command*>( |
239 reinterpret_cast<const uint8_t*>(mach_header) + offset); | 244 reinterpret_cast<const uint8_t*>(mach_header) + offset); |
240 | 245 |
241 if (offset + current_cmd->cmdsize > offset_limit) { | 246 if (offset + current_cmd->cmdsize > offset_limit) { |
242 // This command runs off the end of the command list. This is malformed. | 247 // This command runs off the end of the command list. This is malformed. |
243 return std::string(); | 248 return std::string(); |
244 } | 249 } |
245 | 250 |
246 if (current_cmd->cmd == LC_UUID) { | 251 if (current_cmd->cmd == LC_UUID) { |
247 if (current_cmd->cmdsize < sizeof(uuid_command)) { | 252 if (current_cmd->cmdsize < sizeof(uuid_command)) { |
248 // This "UUID command" is too small. This is malformed. | 253 // This "UUID command" is too small. This is malformed. |
249 return std::string(); | 254 return std::string(); |
250 } | 255 } |
251 | 256 |
252 const uuid_command* uuid_cmd = | 257 const uuid_command* uuid_cmd = |
253 reinterpret_cast<const uuid_command*>(current_cmd); | 258 reinterpret_cast<const uuid_command*>(current_cmd); |
254 static_assert(sizeof(uuid_cmd->uuid) == sizeof(uuid_t), | 259 static_assert(sizeof(uuid_cmd->uuid) == sizeof(uuid_t), |
255 "UUID field of UUID command should be 16 bytes."); | 260 "UUID field of UUID command should be 16 bytes."); |
256 return HexEncode(&uuid_cmd->uuid, sizeof(uuid_cmd->uuid)); | 261 // The ID is comprised of the UUID concatenated with the Mac's "age" value |
| 262 // which is always 0. |
| 263 return HexEncode(&uuid_cmd->uuid, sizeof(uuid_cmd->uuid)) + "0"; |
257 } | 264 } |
258 offset += current_cmd->cmdsize; | 265 offset += current_cmd->cmdsize; |
259 } | 266 } |
260 return std::string(); | 267 return std::string(); |
261 } | 268 } |
262 | 269 |
263 // Gets the index for the Module containing |instruction_pointer| in | 270 // Gets the index for the Module containing |instruction_pointer| in |
264 // |modules|, adding it if it's not already present. Returns | 271 // |modules|, adding it if it's not already present. Returns |
265 // StackSamplingProfiler::Frame::kUnknownModuleIndex if no Module can be | 272 // StackSamplingProfiler::Frame::kUnknownModuleIndex if no Module can be |
266 // determined for |module|. | 273 // determined for |module|. |
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
462 | 469 |
463 std::unique_ptr<NativeStackSampler> NativeStackSampler::Create( | 470 std::unique_ptr<NativeStackSampler> NativeStackSampler::Create( |
464 PlatformThreadId thread_id, | 471 PlatformThreadId thread_id, |
465 AnnotateCallback annotator, | 472 AnnotateCallback annotator, |
466 NativeStackSamplerTestDelegate* test_delegate) { | 473 NativeStackSamplerTestDelegate* test_delegate) { |
467 return base::MakeUnique<NativeStackSamplerMac>(thread_id, annotator, | 474 return base::MakeUnique<NativeStackSamplerMac>(thread_id, annotator, |
468 test_delegate); | 475 test_delegate); |
469 } | 476 } |
470 | 477 |
471 } // namespace base | 478 } // namespace base |
OLD | NEW |