OLD | NEW |
1 // Copyright 2014 The Crashpad Authors. All rights reserved. | 1 // Copyright 2014 The Crashpad Authors. All rights reserved. |
2 // | 2 // |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
4 // you may not use this file except in compliance with 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 | 5 // You may obtain a copy of the License at |
6 // | 6 // |
7 // http://www.apache.org/licenses/LICENSE-2.0 | 7 // http://www.apache.org/licenses/LICENSE-2.0 |
8 // | 8 // |
9 // Unless required by applicable law or agreed to in writing, software | 9 // Unless required by applicable law or agreed to in writing, software |
10 // distributed under the License is distributed on an "AS IS" BASIS, | 10 // distributed under the License is distributed on an "AS IS" BASIS, |
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 // See the License for the specific language governing permissions and | 12 // See the License for the specific language governing permissions and |
13 // limitations under the License. | 13 // limitations under the License. |
14 | 14 |
15 #include "util/mach/task_memory.h" | 15 #include "util/mach/task_memory.h" |
16 | 16 |
17 #include <mach/mach_vm.h> | 17 #include <mach/mach_vm.h> |
18 #include <string.h> | 18 #include <string.h> |
19 | 19 |
20 #include <algorithm> | 20 #include <algorithm> |
21 | 21 |
22 #include "base/logging.h" | 22 #include "base/logging.h" |
23 #include "base/mac/mach_logging.h" | 23 #include "base/mac/mach_logging.h" |
24 #include "base/mac/scoped_mach_vm.h" | |
25 #include "base/strings/stringprintf.h" | 24 #include "base/strings/stringprintf.h" |
| 25 #include "util/stdlib/strnlen.h" |
26 | 26 |
27 namespace crashpad { | 27 namespace crashpad { |
28 | 28 |
| 29 TaskMemory::MappedMemory::~MappedMemory() { |
| 30 } |
| 31 |
| 32 bool TaskMemory::MappedMemory::ReadCString( |
| 33 size_t offset, std::string* string) const { |
| 34 if (offset >= user_size_) { |
| 35 LOG(WARNING) << "offset out of range"; |
| 36 return false; |
| 37 } |
| 38 |
| 39 const char* string_base = reinterpret_cast<const char*>(data_) + offset; |
| 40 size_t max_length = user_size_ - offset; |
| 41 size_t string_length = strnlen(string_base, max_length); |
| 42 if (string_length == max_length) { |
| 43 LOG(WARNING) << "unterminated string"; |
| 44 return false; |
| 45 } |
| 46 |
| 47 string->assign(string_base, string_length); |
| 48 return true; |
| 49 } |
| 50 |
| 51 TaskMemory::MappedMemory::MappedMemory(vm_address_t vm_address, |
| 52 size_t vm_size, |
| 53 size_t user_offset, |
| 54 size_t user_size) |
| 55 : vm_(vm_address, vm_size), |
| 56 data_(reinterpret_cast<const void*>(vm_address + user_offset)), |
| 57 user_size_(user_size) { |
| 58 vm_address_t vm_end = vm_address + vm_size; |
| 59 vm_address_t user_address = reinterpret_cast<vm_address_t>(data_); |
| 60 vm_address_t user_end = user_address + user_size; |
| 61 DCHECK_GE(user_address, vm_address); |
| 62 DCHECK_LE(user_address, vm_end); |
| 63 DCHECK_GE(user_end, vm_address); |
| 64 DCHECK_LE(user_end, vm_end); |
| 65 } |
| 66 |
29 TaskMemory::TaskMemory(mach_port_t task) : task_(task) { | 67 TaskMemory::TaskMemory(mach_port_t task) : task_(task) { |
30 } | 68 } |
31 | 69 |
32 bool TaskMemory::Read(mach_vm_address_t address, size_t size, void* buffer) { | 70 bool TaskMemory::Read(mach_vm_address_t address, size_t size, void* buffer) { |
| 71 scoped_ptr<MappedMemory> memory = ReadMapped(address, size); |
| 72 if (!memory) { |
| 73 return false; |
| 74 } |
| 75 |
| 76 memcpy(buffer, memory->data(), size); |
| 77 return true; |
| 78 } |
| 79 |
| 80 scoped_ptr<TaskMemory::MappedMemory> TaskMemory::ReadMapped( |
| 81 mach_vm_address_t address, size_t size) { |
33 if (size == 0) { | 82 if (size == 0) { |
34 return true; | 83 return scoped_ptr<MappedMemory>(new MappedMemory(0, 0, 0, 0)); |
35 } | 84 } |
36 | 85 |
37 mach_vm_address_t region_address = mach_vm_trunc_page(address); | 86 mach_vm_address_t region_address = mach_vm_trunc_page(address); |
38 mach_vm_size_t region_size = | 87 mach_vm_size_t region_size = |
39 mach_vm_round_page(address - region_address + size); | 88 mach_vm_round_page(address - region_address + size); |
40 | 89 |
41 vm_offset_t region; | 90 vm_offset_t region; |
42 mach_msg_type_number_t region_count; | 91 mach_msg_type_number_t region_count; |
43 kern_return_t kr = | 92 kern_return_t kr = |
44 mach_vm_read(task_, region_address, region_size, ®ion, ®ion_count); | 93 mach_vm_read(task_, region_address, region_size, ®ion, ®ion_count); |
45 if (kr != KERN_SUCCESS) { | 94 if (kr != KERN_SUCCESS) { |
46 MACH_LOG(WARNING, kr) << base::StringPrintf( | 95 MACH_LOG(WARNING, kr) << base::StringPrintf( |
47 "mach_vm_read(0x%llx, 0x%llx)", region_address, region_size); | 96 "mach_vm_read(0x%llx, 0x%llx)", region_address, region_size); |
48 return false; | 97 return scoped_ptr<MappedMemory>(); |
49 } | 98 } |
50 | 99 |
51 DCHECK_EQ(region_count, region_size); | 100 DCHECK_EQ(region_count, region_size); |
52 base::mac::ScopedMachVM region_owner(region, region_count); | 101 return scoped_ptr<MappedMemory>( |
53 | 102 new MappedMemory(region, region_size, address - region_address, size)); |
54 const char* region_base = reinterpret_cast<const char*>(region); | |
55 memcpy(buffer, ®ion_base[address - region_address], size); | |
56 | |
57 return true; | |
58 } | 103 } |
59 | 104 |
60 bool TaskMemory::ReadCString(mach_vm_address_t address, std::string* string) { | 105 bool TaskMemory::ReadCString(mach_vm_address_t address, std::string* string) { |
61 return ReadCStringInternal(address, false, 0, string); | 106 return ReadCStringInternal(address, false, 0, string); |
62 } | 107 } |
63 | 108 |
64 bool TaskMemory::ReadCStringSizeLimited(mach_vm_address_t address, | 109 bool TaskMemory::ReadCStringSizeLimited(mach_vm_address_t address, |
65 mach_vm_size_t size, | 110 mach_vm_size_t size, |
66 std::string* string) { | 111 std::string* string) { |
67 return ReadCStringInternal(address, true, size, string); | 112 return ReadCStringInternal(address, true, size, string); |
(...skipping 10 matching lines...) Expand all Loading... |
78 } | 123 } |
79 } else { | 124 } else { |
80 size = PAGE_SIZE; | 125 size = PAGE_SIZE; |
81 } | 126 } |
82 | 127 |
83 std::string local_string; | 128 std::string local_string; |
84 mach_vm_address_t read_address = address; | 129 mach_vm_address_t read_address = address; |
85 do { | 130 do { |
86 mach_vm_size_t read_length = | 131 mach_vm_size_t read_length = |
87 std::min(size, PAGE_SIZE - (read_address % PAGE_SIZE)); | 132 std::min(size, PAGE_SIZE - (read_address % PAGE_SIZE)); |
88 std::string read_string(read_length, '\0'); | 133 scoped_ptr<MappedMemory> read_region = |
89 if (!Read(read_address, read_length, &read_string[0])) { | 134 ReadMapped(read_address, read_length); |
| 135 if (!read_region) { |
90 return false; | 136 return false; |
91 } | 137 } |
92 | 138 |
93 size_t terminator = read_string.find_first_of('\0'); | 139 const char* read_region_data = |
94 if (terminator == std::string::npos) { | 140 reinterpret_cast<const char*>(read_region->data()); |
95 local_string.append(read_string); | 141 size_t read_region_data_length = strnlen(read_region_data, read_length); |
96 } else { | 142 local_string.append(read_region_data, read_region_data_length); |
97 local_string.append(read_string, 0, terminator); | 143 if (read_region_data_length < read_length) { |
98 string->swap(local_string); | 144 string->swap(local_string); |
99 return true; | 145 return true; |
100 } | 146 } |
101 | 147 |
102 if (has_size) { | 148 if (has_size) { |
103 size -= read_length; | 149 size -= read_length; |
104 } | 150 } |
105 read_address = mach_vm_trunc_page(read_address + read_length); | 151 read_address = mach_vm_trunc_page(read_address + read_length); |
106 } while ((!has_size || size > 0) && read_address > address); | 152 } while ((!has_size || size > 0) && read_address > address); |
107 | 153 |
108 LOG(WARNING) << base::StringPrintf("unterminated string at 0x%llx", address); | 154 LOG(WARNING) << base::StringPrintf("unterminated string at 0x%llx", address); |
109 return false; | 155 return false; |
110 } | 156 } |
111 | 157 |
112 } // namespace crashpad | 158 } // namespace crashpad |
OLD | NEW |