[llvm-commits] [compiler-rt] r148472 - in /compiler-rt/trunk/lib/asan: asan_mac.cc asan_procmaps.h
Alexander Potapenko
glider at google.com
Thu Jan 19 04:44:06 PST 2012
Author: glider
Date: Thu Jan 19 06:44:06 2012
New Revision: 148472
URL: http://llvm.org/viewvc/llvm-project?rev=148472&view=rev
Log:
Minor fixes of the AsanProcMaps code on Mac:
-- make the load command scan linear (instead of quadratic)
-- do not create a nested AsanProcMaps instance for each address lookup
-- more comments
Modified:
compiler-rt/trunk/lib/asan/asan_mac.cc
compiler-rt/trunk/lib/asan/asan_procmaps.h
Modified: compiler-rt/trunk/lib/asan/asan_mac.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_mac.cc?rev=148472&r1=148471&r2=148472&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_mac.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_mac.cc Thu Jan 19 06:44:06 2012
@@ -154,37 +154,51 @@
AsanProcMaps::~AsanProcMaps() {
}
+// More information about Mach-O headers can be found in mach-o/loader.h
+// Each Mach-O image has a header (mach_header or mach_header_64) starting with
+// a magic number, and a list of linker load commands directly following the
+// header.
+// A load command is at least two 32-bit words: the command type and the
+// command size in bytes. We're interested only in segment load commands
+// (LC_SEGMENT and LC_SEGMENT_64), which tell that a part of the file is mapped
+// into the task's address space.
+// The |vmaddr|, |vmsize| and |fileoff| fields of segment_command or
+// segment_command_64 correspond to the memory address, memory size and the
+// file offset of the current memory segment.
+// Because these fields are taken from the images as is, one needs to add
+// _dyld_get_image_vmaddr_slide() to get the actual addresses at runtime.
+
void AsanProcMaps::Reset() {
// Count down from the top.
// TODO(glider): as per man 3 dyld, iterating over the headers with
- // _dyld_image_count is thread-unsafe.
+ // _dyld_image_count is thread-unsafe. We need to register callbacks for
+ // adding and removing images which will invalidate the AsanProcMaps state.
current_image_ = _dyld_image_count();
- current_load_cmd_ = -1;
+ current_load_cmd_count_ = -1;
+ current_load_cmd_addr_ = NULL;
}
-// Similar code is used in Google Perftools,
-// http://code.google.com/p/google-perftools.
-template<uint32_t kMagic, uint32_t kLCSegment,
- typename MachHeader, typename SegmentCommand>
-static bool NextExtMachHelper(const mach_header* hdr,
- int current_image, int current_load_cmd,
- uintptr_t *start, uintptr_t *end,
- uintptr_t *offset,
- char filename[], size_t filename_size) {
- if (hdr->magic != kMagic)
- return false;
- const char* lc = (const char *)hdr + sizeof(MachHeader);
- // TODO(csilvers): make this not-quadradic (increment and hold state)
- for (int j = 0; j < current_load_cmd; j++) // advance to *our* load_cmd
- lc += ((const load_command *)lc)->cmdsize;
+// Next and NextSegmentLoad were inspired by base/sysinfo.cc in
+// Google Perftools, http://code.google.com/p/google-perftools.
+
+// NextSegmentLoad scans the current image for the next segment load command
+// and returns the start and end addresses and file offset of the corresponding
+// segment.
+// Note that the segment addresses are not necessarily sorted.
+template<uint32_t kLCSegment, typename SegmentCommand>
+bool AsanProcMaps::NextSegmentLoad(
+ uintptr_t *start, uintptr_t *end, uintptr_t *offset,
+ char filename[], size_t filename_size) {
+ const char* lc = current_load_cmd_addr_;
+ current_load_cmd_addr_ += ((const load_command *)lc)->cmdsize;
if (((const load_command *)lc)->cmd == kLCSegment) {
- const intptr_t dlloff = _dyld_get_image_vmaddr_slide(current_image);
+ const intptr_t dlloff = _dyld_get_image_vmaddr_slide(current_image_);
const SegmentCommand* sc = (const SegmentCommand *)lc;
if (start) *start = sc->vmaddr + dlloff;
if (end) *end = sc->vmaddr + sc->vmsize + dlloff;
if (offset) *offset = sc->fileoff;
if (filename) {
- real_strncpy(filename, _dyld_get_image_name(current_image),
+ real_strncpy(filename, _dyld_get_image_name(current_image_),
filename_size);
}
return true;
@@ -195,37 +209,45 @@
bool AsanProcMaps::Next(uintptr_t *start, uintptr_t *end,
uintptr_t *offset, char filename[],
size_t filename_size) {
- // We return a separate entry for each segment in the DLL. (TODO(csilvers):
- // can we do better?) A DLL ("image") has load-commands, some of which
- // talk about segment boundaries.
- // cf image_for_address from http://svn.digium.com/view/asterisk/team/oej/minivoicemail/dlfcn.c?revision=53912
for (; current_image_ >= 0; current_image_--) {
const mach_header* hdr = _dyld_get_image_header(current_image_);
if (!hdr) continue;
- if (current_load_cmd_ < 0) // set up for this image
- current_load_cmd_ = hdr->ncmds; // again, go from the top down
+ if (current_load_cmd_count_ < 0) {
+ // Set up for this image;
+ current_load_cmd_count_ = hdr->ncmds;
+ switch (hdr->magic) {
+#ifdef MH_MAGIC_64
+ case MH_MAGIC_64: {
+ current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header_64);
+ break;
+ }
+#endif
+ case MH_MAGIC: {
+ current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header);
+ break;
+ }
+ default: {
+ continue;
+ }
+ }
+ }
// We start with the next load command (we've already looked at this one).
- for (current_load_cmd_--; current_load_cmd_ >= 0; current_load_cmd_--) {
+ for (current_load_cmd_count_--;
+ current_load_cmd_count_ >= 0;
+ current_load_cmd_count_--) {
#ifdef MH_MAGIC_64
- if (NextExtMachHelper<MH_MAGIC_64, LC_SEGMENT_64,
- struct mach_header_64, struct segment_command_64>(
- hdr, current_image_, current_load_cmd_,
- start, end, offset, filename, filename_size)) {
+ if (NextSegmentLoad<LC_SEGMENT_64, struct segment_command_64>(
+ start, end, offset, filename, filename_size))
return true;
- }
#endif
- if (NextExtMachHelper<MH_MAGIC, LC_SEGMENT,
- struct mach_header, struct segment_command>(
- hdr, current_image_, current_load_cmd_,
- start, end, offset, filename, filename_size)) {
+ if (NextSegmentLoad<LC_SEGMENT, struct segment_command>(
+ start, end, offset, filename, filename_size))
return true;
- }
}
// If we get here, no more load_cmd's in this image talk about
// segments. Go on to the next image.
}
- // We didn't find anything.
return false;
}
Modified: compiler-rt/trunk/lib/asan/asan_procmaps.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_procmaps.h?rev=148472&r1=148471&r2=148472&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_procmaps.h (original)
+++ compiler-rt/trunk/lib/asan/asan_procmaps.h Thu Jan 19 06:44:06 2012
@@ -15,6 +15,9 @@
#define ASAN_PROCMAPS_H
#include "asan_internal.h"
+#if defined __APPLE__
+#include <mach-o/loader.h>
+#endif
namespace __asan {
@@ -30,15 +33,21 @@
char filename[], size_t filename_size);
~AsanProcMaps();
private:
+#if defined __APPLE__
+ template<uint32_t kLCSegment, typename SegmentCommand>
+ bool NextSegmentLoad(uintptr_t *start, uintptr_t *end, uintptr_t *offset,
+ char filename[], size_t filename_size);
+#endif
// Default implementation of GetObjectNameAndOffset.
// Quite slow, because it iterates through the whole process map for each
// lookup.
bool IterateForObjectNameAndOffset(uintptr_t addr, uintptr_t *offset,
char filename[], size_t filename_size) {
- AsanProcMaps proc_maps;
+ Reset();
uintptr_t start, end, file_offset;
- while (proc_maps.Next(&start, &end, &file_offset,
- filename, filename_size)) {
+ while (Next(&start, &end, &file_offset,
+ filename, filename_size)) {
+ Report("%p--%p, %s\n", start, end, filename);
if (addr >= start && addr < end) {
*offset = (addr - start) + file_offset;
return true;
@@ -56,7 +65,8 @@
char *current_;
#elif defined __APPLE__
int current_image_;
- int current_load_cmd_;
+ int current_load_cmd_count_;
+ char *current_load_cmd_addr_;
#endif
};
More information about the llvm-commits
mailing list