OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 The Crashpad Authors. All rights reserved. |
| 2 // |
| 3 // Licensed under the Apache License, Version 2.0 (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 |
| 6 // |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 // |
| 9 // Unless required by applicable law or agreed to in writing, software |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 // See the License for the specific language governing permissions and |
| 13 // limitations under the License. |
| 14 |
| 15 #include "util/mach/task_memory.h" |
| 16 |
| 17 #include <mach/mach_vm.h> |
| 18 #include <string.h> |
| 19 |
| 20 #include <algorithm> |
| 21 |
| 22 #include "base/logging.h" |
| 23 #include "base/mac/mach_logging.h" |
| 24 #include "base/mac/scoped_mach_vm.h" |
| 25 #include "base/strings/stringprintf.h" |
| 26 |
| 27 namespace crashpad { |
| 28 |
| 29 TaskMemory::TaskMemory(mach_port_t task) : task_(task) { |
| 30 } |
| 31 |
| 32 bool TaskMemory::Read(mach_vm_address_t address, size_t size, void* buffer) { |
| 33 if (size == 0) { |
| 34 return true; |
| 35 } |
| 36 |
| 37 mach_vm_address_t region_address = mach_vm_trunc_page(address); |
| 38 mach_vm_size_t region_size = |
| 39 mach_vm_round_page(address - region_address + size); |
| 40 |
| 41 vm_offset_t region; |
| 42 mach_msg_type_number_t region_count; |
| 43 kern_return_t kr = |
| 44 mach_vm_read(task_, region_address, region_size, ®ion, ®ion_count); |
| 45 if (kr != KERN_SUCCESS) { |
| 46 MACH_LOG(WARNING, kr) << base::StringPrintf( |
| 47 "mach_vm_read(0x%llx, 0x%llx)", region_address, region_size); |
| 48 return false; |
| 49 } |
| 50 |
| 51 DCHECK_EQ(region_count, region_size); |
| 52 base::mac::ScopedMachVM region_owner(region, region_count); |
| 53 |
| 54 const char* region_base = reinterpret_cast<const char*>(region); |
| 55 memcpy(buffer, ®ion_base[address - region_address], size); |
| 56 |
| 57 return true; |
| 58 } |
| 59 |
| 60 bool TaskMemory::ReadCString(mach_vm_address_t address, std::string* string) { |
| 61 return ReadCStringInternal(address, false, 0, string); |
| 62 } |
| 63 |
| 64 bool TaskMemory::ReadCStringSizeLimited(mach_vm_address_t address, |
| 65 mach_vm_size_t size, |
| 66 std::string* string) { |
| 67 return ReadCStringInternal(address, true, size, string); |
| 68 } |
| 69 |
| 70 bool TaskMemory::ReadCStringInternal(mach_vm_address_t address, |
| 71 bool has_size, |
| 72 mach_vm_size_t size, |
| 73 std::string* string) { |
| 74 if (has_size) { |
| 75 if (size == 0) { |
| 76 string->clear(); |
| 77 return true; |
| 78 } |
| 79 } else { |
| 80 size = PAGE_SIZE; |
| 81 } |
| 82 |
| 83 std::string local_string; |
| 84 mach_vm_address_t read_address = address; |
| 85 do { |
| 86 mach_vm_size_t read_length = |
| 87 std::min(size, PAGE_SIZE - (read_address % PAGE_SIZE)); |
| 88 std::string read_string(read_length, '\0'); |
| 89 if (!Read(read_address, read_length, &read_string[0])) { |
| 90 return false; |
| 91 } |
| 92 |
| 93 size_t terminator = read_string.find_first_of('\0'); |
| 94 if (terminator == std::string::npos) { |
| 95 local_string.append(read_string); |
| 96 } else { |
| 97 local_string.append(read_string, 0, terminator); |
| 98 string->swap(local_string); |
| 99 return true; |
| 100 } |
| 101 |
| 102 if (has_size) { |
| 103 size -= read_length; |
| 104 } |
| 105 read_address = mach_vm_trunc_page(read_address + read_length); |
| 106 } while ((!has_size || size > 0) && read_address > address); |
| 107 |
| 108 LOG(WARNING) << base::StringPrintf("unterminated string at 0x%llx", address); |
| 109 return false; |
| 110 } |
| 111 |
| 112 } // namespace crashpad |
OLD | NEW |