aboutsummaryrefslogtreecommitdiff
path: root/src/client/mac/handler
diff options
context:
space:
mode:
authorted.mielczarek <ted.mielczarek@4c0a9323-5329-0410-9bdc-e9ce6186880e>2010-09-23 14:55:50 +0000
committerted.mielczarek <ted.mielczarek@4c0a9323-5329-0410-9bdc-e9ce6186880e>2010-09-23 14:55:50 +0000
commit4621ee06914b2ebe963c93ea78fabf982cf670df (patch)
treead6c7f5b0898ca5879e340fdf99772d4936e6403 /src/client/mac/handler
parentAdded the base exploitability module for windows. This only adds the very bas... (diff)
downloadbreakpad-4621ee06914b2ebe963c93ea78fabf982cf670df.tar.xz
Write a window of memory around the instruction pointer from the crashing thread to the minidump on OS X.
R=nealsid at http://breakpad.appspot.com/200001/show git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@699 4c0a9323-5329-0410-9bdc-e9ce6186880e
Diffstat (limited to 'src/client/mac/handler')
-rw-r--r--src/client/mac/handler/minidump_generator.cc122
-rw-r--r--src/client/mac/handler/minidump_generator.h13
2 files changed, 132 insertions, 3 deletions
diff --git a/src/client/mac/handler/minidump_generator.cc b/src/client/mac/handler/minidump_generator.cc
index 0c54cf42..73086743 100644
--- a/src/client/mac/handler/minidump_generator.cc
+++ b/src/client/mac/handler/minidump_generator.cc
@@ -27,6 +27,7 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#include <algorithm>
#include <cstdio>
#include <mach/host_info.h>
@@ -64,7 +65,8 @@ MinidumpGenerator::MinidumpGenerator()
exception_thread_(0),
crashing_task_(mach_task_self()),
handler_thread_(mach_thread_self()),
- dynamic_images_(NULL) {
+ dynamic_images_(NULL),
+ memory_blocks_(&allocator_) {
GatherSystemInformation();
}
@@ -79,7 +81,8 @@ MinidumpGenerator::MinidumpGenerator(mach_port_t crashing_task,
exception_thread_(0),
crashing_task_(crashing_task),
handler_thread_(handler_thread),
- dynamic_images_(NULL) {
+ dynamic_images_(NULL),
+ memory_blocks_(&allocator_) {
if (crashing_task != mach_task_self()) {
dynamic_images_ = new DynamicImages(crashing_task_);
} else {
@@ -173,6 +176,7 @@ string MinidumpGenerator::UniqueNameInDirectory(const string &dir,
bool MinidumpGenerator::Write(const char *path) {
WriteStreamFN writers[] = {
&MinidumpGenerator::WriteThreadListStream,
+ &MinidumpGenerator::WriteMemoryListStream,
&MinidumpGenerator::WriteSystemInfoStream,
&MinidumpGenerator::WriteModuleListStream,
&MinidumpGenerator::WriteMiscInfoStream,
@@ -514,6 +518,8 @@ bool MinidumpGenerator::WriteThreadStream(mach_port_t thread_id,
if (!WriteStack(state, &thread->stack))
return false;
+ memory_blocks_.push_back(thread->stack);
+
if (!WriteContext(state, &thread->thread_context))
return false;
@@ -566,6 +572,118 @@ bool MinidumpGenerator::WriteThreadListStream(
return true;
}
+bool MinidumpGenerator::WriteMemoryListStream(
+ MDRawDirectory *memory_list_stream) {
+ TypedMDRVA<MDRawMemoryList> list(&writer_);
+
+ // If the dump has an exception, include some memory around the
+ // instruction pointer.
+ const size_t kIPMemorySize = 256; // bytes
+ bool have_ip_memory = false;
+ MDMemoryDescriptor ip_memory_d;
+ if (exception_thread_ && exception_type_) {
+ breakpad_thread_state_data_t state;
+ mach_msg_type_number_t stateCount
+ = static_cast<mach_msg_type_number_t>(sizeof(state));
+
+ if (thread_get_state(exception_thread_,
+ BREAKPAD_MACHINE_THREAD_STATE,
+ state,
+ &stateCount) == KERN_SUCCESS) {
+ u_int64_t ip = CurrentPCForStack(state);
+ // Bound it to the upper and lower bounds of the region
+ // it's contained within. If it's not in a known memory region,
+ // don't bother trying to write it.
+ mach_vm_address_t addr = ip;
+ mach_vm_size_t size;
+ natural_t nesting_level = 0;
+ vm_region_submap_info_64 info;
+ mach_msg_type_number_t info_count = VM_REGION_SUBMAP_INFO_COUNT_64;
+
+ kern_return_t ret =
+ mach_vm_region_recurse(crashing_task_,
+ &addr,
+ &size,
+ &nesting_level,
+ (vm_region_recurse_info_t)&info,
+ &info_count);
+ if (ret == KERN_SUCCESS && ip >= addr && ip < (addr + size)) {
+ // Try to get 128 bytes before and after the IP, but
+ // settle for whatever's available.
+ ip_memory_d.start_of_memory_range =
+ std::max(uintptr_t(addr),
+ uintptr_t(ip - (kIPMemorySize / 2)));
+ uintptr_t end_of_range =
+ std::min(uintptr_t(ip + (kIPMemorySize / 2)),
+ uintptr_t(addr + size));
+ ip_memory_d.memory.data_size =
+ end_of_range - ip_memory_d.start_of_memory_range;
+ have_ip_memory = true;
+ // This needs to get appended to the list even though
+ // the memory bytes aren't filled in yet so the entire
+ // list can be written first. The memory bytes will get filled
+ // in after the memory list is written.
+ memory_blocks_.push_back(ip_memory_d);
+ }
+ }
+ }
+
+ // Now fill in the memory list and write it.
+ unsigned memory_count = memory_blocks_.size();
+ if (!list.AllocateObjectAndArray(memory_count,
+ sizeof(MDMemoryDescriptor)))
+ return false;
+
+ memory_list_stream->stream_type = MD_MEMORY_LIST_STREAM;
+ memory_list_stream->location = list.location();
+
+ list.get()->number_of_memory_ranges = memory_count;
+
+ unsigned int i;
+ for (i = 0; i < memory_count; ++i) {
+ list.CopyIndexAfterObject(i++, &memory_blocks_[i],
+ sizeof(MDMemoryDescriptor));
+ }
+
+ if (have_ip_memory) {
+ // Now read the memory around the instruction pointer.
+ UntypedMDRVA ip_memory(&writer_);
+ if (!ip_memory.Allocate(ip_memory_d.memory.data_size))
+ return false;
+
+ if (dynamic_images_) {
+ // Out-of-process.
+ kern_return_t kr;
+
+ void *memory =
+ ReadTaskMemory(
+ crashing_task_,
+ reinterpret_cast<const void *>(ip_memory_d.start_of_memory_range),
+ ip_memory_d.memory.data_size,
+ &kr);
+
+ if (memory == NULL) {
+ return false;
+ }
+
+ ip_memory.Copy(memory, ip_memory_d.memory.data_size);
+ free(memory);
+ } else {
+ // In-process, just copy from local memory.
+ ip_memory.Copy(
+ reinterpret_cast<const void *>(ip_memory_d.start_of_memory_range),
+ ip_memory_d.memory.data_size);
+ }
+
+ ip_memory_d.memory = ip_memory.location();
+ // Write this again now that the data location is filled in.
+ list.CopyIndexAfterObject(i - 1, &ip_memory_d,
+ sizeof(MDMemoryDescriptor));
+ }
+
+ return true;
+}
+
bool
MinidumpGenerator::WriteExceptionStream(MDRawDirectory *exception_stream) {
TypedMDRVA<MDRawExceptionStream> exception(&writer_);
diff --git a/src/client/mac/handler/minidump_generator.h b/src/client/mac/handler/minidump_generator.h
index b065fba9..39f28402 100644
--- a/src/client/mac/handler/minidump_generator.h
+++ b/src/client/mac/handler/minidump_generator.h
@@ -37,8 +37,9 @@
#include <string>
#include "client/minidump_file_writer.h"
-#include "google_breakpad/common/minidump_format.h"
+#include "common/memory.h"
#include "common/mac/macho_utilities.h"
+#include "google_breakpad/common/minidump_format.h"
#include "dynamic_images.h"
@@ -119,6 +120,7 @@ class MinidumpGenerator {
// Stream writers
bool WriteThreadListStream(MDRawDirectory *thread_list_stream);
+ bool WriteMemoryListStream(MDRawDirectory *memory_list_stream);
bool WriteExceptionStream(MDRawDirectory *exception_stream);
bool WriteSystemInfoStream(MDRawDirectory *system_info_stream);
bool WriteModuleListStream(MDRawDirectory *module_list_stream);
@@ -165,6 +167,15 @@ class MinidumpGenerator {
// Information about dynamically loaded code
DynamicImages *dynamic_images_;
+
+ // PageAllocator makes it possible to allocate memory
+ // directly from the system, even while handling an exception.
+ mutable PageAllocator allocator_;
+
+ // Blocks of memory written to the dump. These are all currently
+ // written while writing the thread list stream, but saved here
+ // so a memory list stream can be written afterwards.
+ wasteful_vector<MDMemoryDescriptor> memory_blocks_;
};
} // namespace google_breakpad