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

Unified Diff: util/mac/process_reader.cc

Issue 546573002: Implement (and test) ProcessReader::Modules() (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: Address review feedback 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « util/mac/process_reader.h ('k') | util/mac/process_reader_test.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: util/mac/process_reader.cc
diff --git a/util/mac/process_reader.cc b/util/mac/process_reader.cc
index 7013f7ec70ff88c5bfd44e9aa9d8e737490ab351..fbe5ff07e19656dddaa0dc3375188641a1b896ff 100644
--- a/util/mac/process_reader.cc
+++ b/util/mac/process_reader.cc
@@ -24,6 +24,8 @@
#include "base/mac/mach_logging.h"
#include "base/mac/scoped_mach_port.h"
#include "base/mac/scoped_mach_vm.h"
+#include "util/mac/mach_o_image_reader.h"
+#include "util/mac/process_types.h"
#include "util/misc/scoped_forbid_return.h"
namespace {
@@ -352,11 +354,119 @@ void ProcessReader::InitializeModules() {
initialized_modules_ = true;
- // TODO(mark): Complete this implementation. The implementation depends on
- // process_types, which cannot land yet because it depends on this file,
- // process_reader. This temporary “cut” was made to avoid a review that’s too
- // large. Yes, this circular dependency is unfortunate. Suggestions are
- // welcome.
+ // This API only works on Mac OS X 10.6 and higher. On Mac OS X 10.5, find the
+ // “_dyld_all_image_infos” symbol in the loaded LC_LOAD_DYLINKER (dyld).
+ task_dyld_info_data_t dyld_info;
+ mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
+ kern_return_t kr = task_info(
+ task_, TASK_DYLD_INFO, reinterpret_cast<task_info_t>(&dyld_info), &count);
+ if (kr != KERN_SUCCESS) {
+ MACH_LOG(WARNING, kr) << "task_info";
+ return;
+ }
+
+ // TODO(mark): Deal with statically linked executables which don’t use dyld.
+ // This may look for the module that matches the executable path in the same
+ // data set that vmmap uses.
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
+ // The task_dyld_info_data_t struct grew in 10.7, adding the format field.
+ // Don’t check this field if it’s not present, which can happen when either
+ // the SDK used at compile time or the kernel at run time are too old and
+ // don’t know about it.
+ if (count >= TASK_DYLD_INFO_COUNT) {
+ const integer_t kExpectedFormat =
+ !Is64Bit() ? TASK_DYLD_ALL_IMAGE_INFO_32 : TASK_DYLD_ALL_IMAGE_INFO_64;
+ if (dyld_info.all_image_info_format != kExpectedFormat) {
+ LOG(WARNING) << "unexpected task_dyld_info_data_t::all_image_info_format "
+ << dyld_info.all_image_info_format;
+ DCHECK_EQ(dyld_info.all_image_info_format, kExpectedFormat);
+ return;
+ }
+ }
+#endif
+
+ process_types::dyld_all_image_infos all_image_infos;
+ if (!all_image_infos.Read(this, dyld_info.all_image_info_addr)) {
+ LOG(WARNING) << "could not read dyld_all_image_infos";
+ return;
+ }
+
+ // Note that all_image_infos.infoArrayCount may be 0 if a crash occurred while
+ // dyld was loading the executable. This can happen if a required dynamic
+ // library was not found.
+ DCHECK_GE(all_image_infos.version, 1u);
+ DCHECK_NE(all_image_infos.infoArray, static_cast<mach_vm_address_t>(NULL));
+
+ std::vector<process_types::dyld_image_info> image_info_vector(
+ all_image_infos.infoArrayCount);
+ if (!process_types::dyld_image_info::ReadArrayInto(this,
+ all_image_infos.infoArray,
+ image_info_vector.size(),
+ &image_info_vector[0])) {
+ LOG(WARNING) << "could not read dyld_image_info array";
+ return;
+ }
+
+ bool found_dyld = false;
+ for (const process_types::dyld_image_info& image_info : image_info_vector) {
+ ProcessReaderModule module;
+ module.address = image_info.imageLoadAddress;
+ module.timestamp = image_info.imageFileModDate;
+ if (!task_memory_->ReadCString(image_info.imageFilePath, &module.name)) {
+ LOG(WARNING) << "could not read dyld_image_info::imageFilePath";
+ // Proceed anyway with an empty module name.
+ }
+
+ modules_.push_back(module);
+
+ if (all_image_infos.version >= 2 && all_image_infos.dyldImageLoadAddress &&
+ image_info.imageLoadAddress == all_image_infos.dyldImageLoadAddress) {
+ found_dyld = true;
+ }
+ }
+
+ // all_image_infos.infoArray doesn’t include an entry for dyld, but dyld is
+ // loaded into the process’ address space as a module. Its load address is
+ // easily known given a sufficiently recent all_image_infos.version, but the
+ // timestamp and pathname are not given as they are for other modules.
+ //
+ // The timestamp is a lost cause, because the kernel doesn’t record the
+ // timestamp of the dynamic linker at the time it’s loaded in the same way
+ // that dyld records the timestamps of other modules when they’re loaded. (The
+ // timestamp for the main executable is also not reported and appears as 0
+ // even when accessed via dyld APIs, because it’s loaded by the kernel, not by
+ // dyld.)
+ //
+ // The name can be determined, but it’s not as simple as hardcoding the
+ // default "/usr/lib/dyld" because an executable could have specified anything
+ // in its LC_LOAD_DYLINKER command.
+ if (!found_dyld && all_image_infos.version >= 2 &&
+ all_image_infos.dyldImageLoadAddress) {
+ ProcessReaderModule module;
+ module.address = all_image_infos.dyldImageLoadAddress;
+ module.timestamp = 0;
+
+ // Examine the executable’s LC_LOAD_DYLINKER load command to find the path
+ // used to load dyld.
+ MachOImageReader executable;
+ if (all_image_infos.infoArrayCount >= 1 &&
+ executable.Initialize(this, modules_[0].address, modules_[0].name) &&
+ executable.FileType() == MH_EXECUTE &&
+ !executable.DylinkerName().empty()) {
+ module.name = executable.DylinkerName();
+ } else {
+ // Look inside dyld directly to find its preferred path.
+ MachOImageReader dyld;
+ if (dyld.Initialize(this, module.address, "(dyld)") &&
+ dyld.FileType() == MH_DYLINKER && !dyld.DylinkerName().empty()) {
+ module.name = dyld.DylinkerName();
+ }
+ }
+
+ // dyld is loaded in the process even if its path can’t be determined.
+ modules_.push_back(module);
+ }
}
mach_vm_address_t ProcessReader::CalculateStackRegion(
« no previous file with comments | « util/mac/process_reader.h ('k') | util/mac/process_reader_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698