proc_maps_linux.cc
1 // Copyright 2013 Google LLC 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef __STDC_FORMAT_MACROS 6 #define __STDC_FORMAT_MACROS 7 #endif 8 9 #ifdef HAVE_CONFIG_H 10 #include <config.h> // Must come first 11 #endif 12 13 #include "google_breakpad/processor/proc_maps_linux.h" 14 15 #include <fcntl.h> 16 #include <inttypes.h> 17 #include <stdio.h> 18 19 #include "common/using_std_string.h" 20 #include "processor/logging.h" 21 22 #if defined(OS_ANDROID) && !defined(__LP64__) 23 // In 32-bit mode, Bionic's inttypes.h defines PRI/SCNxPTR as an 24 // unsigned long int, which is incompatible with Bionic's stdint.h 25 // defining uintptr_t as an unsigned int: 26 // https://code.google.com/p/android/issues/detail?id=57218 27 #undef SCNxPTR 28 #define SCNxPTR "x" 29 #endif 30 31 namespace google_breakpad { 32 33 bool ParseProcMaps(const string& input, 34 std::vector<MappedMemoryRegion>* regions_out) { 35 std::vector<MappedMemoryRegion> regions; 36 37 // This isn't async safe nor terribly efficient, but it doesn't need to be at 38 // this point in time. 39 40 // Split the string by newlines. 41 std::vector<string> lines; 42 string l = ""; 43 for (size_t i = 0; i < input.size(); i++) { 44 if (input[i] != '\n' && input[i] != '\r') { 45 l.push_back(input[i]); 46 } else if (l.size() > 0) { 47 lines.push_back(l); 48 l.clear(); 49 } 50 } 51 if (l.size() > 0) { 52 BPLOG(ERROR) << "Input doesn't end in newline"; 53 return false; 54 } 55 56 for (size_t i = 0; i < lines.size(); ++i) { 57 MappedMemoryRegion region; 58 const char* line = lines[i].c_str(); 59 char permissions[5] = {'\0'}; // Ensure NUL-terminated string. 60 int path_index = 0; 61 62 // Sample format from man 5 proc: 63 // 64 // address perms offset dev inode pathname 65 // 08048000-08056000 r-xp 00000000 03:0c 64593 /usr/sbin/gpm 66 // 67 // The final %n term captures the offset in the input string, which is used 68 // to determine the path name. It *does not* increment the return value. 69 // Refer to man 3 sscanf for details. 70 if (sscanf(line, "%" SCNx64 "-%" SCNx64 " %4c %" SCNx64" %hhx:%hhx %" 71 SCNd64 " %n", ®ion.start, ®ion.end, permissions, 72 ®ion.offset, ®ion.major_device, ®ion.minor_device, 73 ®ion.inode, &path_index) < 7) { 74 BPLOG(ERROR) << "sscanf failed for line: " << line; 75 return false; 76 } 77 78 region.permissions = 0; 79 80 if (permissions[0] == 'r') 81 region.permissions |= MappedMemoryRegion::READ; 82 else if (permissions[0] != '-') 83 return false; 84 85 if (permissions[1] == 'w') 86 region.permissions |= MappedMemoryRegion::WRITE; 87 else if (permissions[1] != '-') 88 return false; 89 90 if (permissions[2] == 'x') 91 region.permissions |= MappedMemoryRegion::EXECUTE; 92 else if (permissions[2] != '-') 93 return false; 94 95 if (permissions[3] == 'p') 96 region.permissions |= MappedMemoryRegion::PRIVATE; 97 else if (permissions[3] != 's' && permissions[3] != 'S') // Shared memory. 98 return false; 99 100 // Pushing then assigning saves us a string copy. 101 regions.push_back(region); 102 regions.back().path.assign(line + path_index); 103 regions.back().line.assign(line); 104 } 105 106 regions_out->swap(regions); 107 return true; 108 } 109 110 } // namespace google_breakpad