Chromium Code Reviews| Index: src/processor/minidump.cc |
| =================================================================== |
| --- src/processor/minidump.cc (revision 1474) |
| +++ src/processor/minidump.cc (working copy) |
| @@ -55,6 +55,7 @@ |
| #include <iostream> |
| #include <limits> |
| #include <map> |
| +#include <sstream> |
| #include <vector> |
| #include "processor/range_map-inl.h" |
| @@ -71,6 +72,7 @@ |
| using std::istream; |
| using std::ifstream; |
| using std::numeric_limits; |
| +using std::stringstream; |
| using std::vector; |
| // Returns true iff |context_size| matches exactly one of the sizes of the |
| @@ -3972,8 +3974,274 @@ |
| } |
| } |
| +// |
| +// MinidumpLinuxMaps |
| +// |
| +MinidumpLinuxMaps::MinidumpLinuxMaps(Minidump *minidump) |
| + : MinidumpObject(minidump), |
| + pathname_(), |
| + raw_linux_maps_(NULL) { |
| +} |
| + |
| +MinidumpLinuxMaps::~MinidumpLinuxMaps() { |
| + delete raw_linux_maps_; |
| +} |
| + |
| +bool MinidumpLinuxMaps::Read(vector<char> *data) { |
|
ivanpe
2015/07/23 01:17:12
There is already an implementation of this in Chro
liuandrew
2015/07/23 16:14:50
How do I reuse the Chromium code? Do I just copy t
liuandrew
2015/07/24 23:25:36
Done.
|
| + valid_ = false; |
| + |
| + // Convert data vector into stringstream. |
| + string str = ""; |
| + for (unsigned int i = 0; i < data->size(); i++) { |
| + str.push_back((*data)[i]); |
| + } |
| + stringstream stream(str); |
| + delete data; |
| + data = NULL; |
| + |
| + // Tokenize the string stream. |
| + string address, perms, offset, dev, inode; |
| + stream >> address >> perms >> offset >> dev >> inode >> pathname_; |
| + // Check if the tokens are filled. The pathname is optional. |
| + if (address.size() <= 0 |
| + || perms.size() <= 0 |
| + || offset.size() <= 0 |
| + || dev.size() <= 0 |
| + || inode.size() <= 0) { |
| + BPLOG(ERROR) << "Malformed input string: not enough tokens"; |
| + return false; |
| + } |
| + |
| + // Load base address and region size. |
| + size_t address_delimiter_index = address.find("-"); |
| + if (address_delimiter_index == string::npos) { |
| + BPLOG(ERROR) << "Address delimiter not found"; |
| + return false; |
| + } |
| + uint64_t end_address = 0; |
| + stringstream(address.substr(0, address_delimiter_index)) |
| + >> std::hex |
| + >> base_address_; |
| + stringstream(address.substr(address_delimiter_index + 1, address.size())) |
| + >> std::hex |
| + >> end_address; |
| + if (base_address_ > end_address) { |
| + BPLOG(ERROR) << "Base address greater than end address: " |
| + << base_address_ |
| + << " > " |
| + << end_address; |
| + return false; |
| + } |
| + region_size_ = end_address - base_address_; |
| + |
| + // Load permissions. |
| + if (perms.size() != 4) { |
| + BPLOG(ERROR) << "Permission string incorrectly loaded"; |
| + return false; |
| + } |
| + if (perms[0] == 'r') { |
| + is_readable_ = true; |
| + } else if (perms[0] == '-') { |
| + is_readable_ = false; |
| + } else { |
| + BPLOG(ERROR) << "Invalid permission character: " << perms[0]; |
| + return false; |
| + } |
| + if (perms[1] == 'w') { |
| + is_writeable_ = true; |
| + } else if (perms[1] == '-') { |
| + is_writeable_ = false; |
| + } else { |
| + BPLOG(ERROR) << "Invalid permission character: " << perms[1]; |
| + return false; |
| + } |
| + if (perms[2] == 'x') { |
| + is_executable_ = true; |
| + } else if (perms[2] == '-') { |
| + is_executable_ = false; |
| + } else { |
| + BPLOG(ERROR) << "Invalid permission character: " << perms[2]; |
| + return false; |
| + } |
| + if (perms[3] == 's') { |
| + is_shared_ = true; |
| + } else if (perms[3] == 'p') { |
| + is_shared_ = false; |
| + } else { |
| + BPLOG(ERROR) << "Invalid permission character: " << perms[3]; |
| + return false; |
| + } |
| + |
| + // Load offset. |
| + stringstream(offset) >> std::hex >> offset_; |
| + |
| + // Load major and minor devices. |
| + size_t device_delimiter_index = dev.find(":"); |
| + if (device_delimiter_index == string::npos) { |
| + BPLOG(ERROR) << "Device delimiter not found"; |
| + return false; |
| + } |
| + uint64_t major_container, minor_container; |
| + stringstream(dev.substr(0, device_delimiter_index)) |
| + >> std::hex |
| + >> major_container; |
| + stringstream(dev.substr(device_delimiter_index + 1, dev.size())) |
| + >> std::hex |
| + >> minor_container; |
| + major_device_ = static_cast<uint8_t>(major_container); |
| + minor_device_ = static_cast<uint8_t>(minor_container); |
| + |
| + // Load inode. |
| + stringstream(inode) >> inode_; |
| + |
| + valid_ = true; |
| + return true; |
| +} |
| + |
| +void MinidumpLinuxMaps::Print() { |
| + if (!valid_) { |
| + BPLOG(ERROR) << "MinidumpLinuxMaps cannot print invalid data"; |
| + return; |
| + } |
| + // Print the contents of raw_linux_maps_. |
| + for (unsigned int i = 0; i < raw_linux_maps_->size(); i++) { |
| + printf("%c", (*raw_linux_maps_)[i]); |
| + } |
| +} |
| + |
| // |
| +// MinidumpLinuxMapsList |
| +// |
| + |
| +MinidumpLinuxMapsList::MinidumpLinuxMapsList(Minidump *minidump) |
| + : MinidumpStream(minidump), |
| + maps_(NULL), |
| + maps_count_(0), |
| + raw_linux_maps_list_() { |
| +} |
| + |
| +MinidumpLinuxMapsList::~MinidumpLinuxMapsList() { |
| + for (unsigned int i = 0; i < maps_->size(); i++) { |
| + delete (*maps_)[i]; |
| + } |
| + delete maps_; |
| +} |
| + |
| +const MinidumpLinuxMaps *MinidumpLinuxMapsList::GetLinuxMapsForAddress( |
| + uint64_t address) const { |
| + if (!valid_) { |
| + BPLOG(ERROR) << "Invalid MinidumpLinuxMapsList for GetLinuxMapsForAddress"; |
| + return NULL; |
| + } |
| + |
| + // Search every memory mapping. |
| + for (unsigned int index = 0; index < maps_count_; index++) { |
| + // Check if address is within bounds of the current memory region. |
| + if ((*maps_)[index]->GetBase() <= address && |
| + (*maps_)[index]->GetBase() + (*maps_)[index]->GetSize() > address) { |
| + return (*maps_)[index]; |
| + } |
| + } |
| + |
| + // No mapping encloses the memory address. |
| + BPLOG(ERROR) << "MinidumpLinuxMapsList has no mapping at " |
| + << HexString(address); |
| + return NULL; |
| +} |
| + |
| +const MinidumpLinuxMaps *MinidumpLinuxMapsList::GetLinuxMapsAtIndex( |
| + unsigned int index) const { |
| + if (!valid_) { |
| + BPLOG(ERROR) << "Invalid MinidumpLinuxMapsList for GetLinuxMapsAtIndex"; |
| + return NULL; |
| + } |
| + |
| + // Index out of bounds. |
| + if (index >= maps_count_) { |
| + BPLOG(ERROR) << "MinidumpLinuxMapsList index of out range: " |
| + << index |
| + << "/" |
| + << maps_count_; |
| + return NULL; |
| + } |
| + return (*maps_)[index]; |
| +} |
| + |
| +bool MinidumpLinuxMapsList::Read(uint32_t expected_size) { |
| + // Invalidate cached data. |
| + delete maps_; |
| + maps_ = NULL; |
| + maps_count_ = 0; |
| + raw_linux_maps_list_.clear(); |
| + |
| + valid_ = false; |
| + |
| + // Load and check expected stream length. |
| + uint32_t length = 0; |
| + if (!minidump_->SeekToStreamType(MD_LINUX_MAPS, &length)) { |
| + BPLOG(ERROR) << "MinidumpLinuxMapsList stream type not found"; |
| + return false; |
| + } |
| + if (expected_size != length) { |
| + BPLOG(ERROR) << "MinidumpLinuxMapsList size mismatch: " |
| + << expected_size |
| + << " != " |
| + << length; |
| + return false; |
| + } |
| + |
| + // Read data from stream into raw_linux_maps_list_. |
| + raw_linux_maps_list_.resize(length); |
| + if (!minidump_->ReadBytes(&raw_linux_maps_list_[0], length)) { |
| + BPLOG(ERROR) << "MinidumpLinuxMapsList failed to read bytes"; |
| + return false; |
| + } |
| + scoped_ptr<vector<char> > map_data(new vector<char>()); |
| + scoped_ptr<MinidumpLinuxMaps> map_entry(new MinidumpLinuxMaps(minidump_)); |
| + scoped_ptr<MinidumpLinuxMappings> maps(new MinidumpLinuxMappings()); |
| + |
| + // Load all of the raw list into a list of MinidumpLinuxMaps. |
| + for (unsigned int i = 0; i < raw_linux_maps_list_.size(); i++) { |
| + // Push character into data buffer. |
| + map_data->push_back(raw_linux_maps_list_[i]); |
| + |
| + // A newline marks the end of a mapping entry. |
| + if (raw_linux_maps_list_[i] == '\n') { |
| + // Read entry data into MinidumpLinuxMaps object. |
| + if (!map_entry->Read(map_data.release())) { |
| + BPLOG(ERROR) << "MinidumpLinuxMapsList failed to read entry"; |
| + return false; |
| + } |
| + // Add completed map entry into vector. |
| + maps->push_back(map_entry.release()); |
| + |
| + // Reset scoped pointers. |
| + map_data.reset(new vector<char>()); |
| + map_entry.reset(new MinidumpLinuxMaps(minidump_)); |
| + } |
| + } |
| + |
| + // Set instance variables. |
| + maps_ = maps.release(); |
| + maps_count_ = maps_->size(); |
| + valid_ = true; |
| + return true; |
| +} |
| + |
| +void MinidumpLinuxMapsList::Print() { |
| + if (!valid_) { |
| + BPLOG(ERROR) << "MinidumpLinuxMapsList cannot print valid data"; |
| + return; |
| + } |
| + |
| + // Print contents of raw_linux_maps_list_. |
| + for (unsigned int i = 0; i < raw_linux_maps_list_.size(); i++) { |
| + printf("%c", raw_linux_maps_list_[i]); |
| + } |
| +} |
| + |
| +// |
| // Minidump |
| // |
| @@ -4292,6 +4560,11 @@ |
| return GetStream(&memory_info_list); |
| } |
| +MinidumpLinuxMapsList *Minidump::GetLinuxMapsList() { |
| + MinidumpLinuxMapsList *linux_maps_list; |
| + return GetStream(&linux_maps_list); |
| +} |
| + |
| static const char* get_stream_name(uint32_t stream_type) { |
| switch (stream_type) { |
| case MD_UNUSED_STREAM: |