--- base/debug/proc_maps_linux.cc.orig	2021-04-14 18:40:48 UTC
+++ base/debug/proc_maps_linux.cc
@@ -13,13 +13,18 @@
 #include "base/strings/string_split.h"
 #include "build/build_config.h"
 
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
+#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) || defined(OS_BSD)
 #include <inttypes.h>
 #endif
 
 namespace base {
 namespace debug {
 
+#if defined(OS_BSD)
+const char kProcSelfMapsPath[] = "/proc/curproc/map";
+#else
+const char kProcSelfMapsPath[] = "/proc/self/maps";
+
 // Scans |proc_maps| starting from |pos| returning true if the gate VMA was
 // found, otherwise returns false.
 static bool ContainsGateVMA(std::string* proc_maps, size_t pos) {
@@ -35,15 +40,16 @@ static bool ContainsGateVMA(std::string* proc_maps, si
   return false;
 #endif
 }
+#endif
 
 bool ReadProcMaps(std::string* proc_maps) {
   // seq_file only writes out a page-sized amount on each call. Refer to header
   // file for details.
   const long kReadSize = sysconf(_SC_PAGESIZE);
 
-  base::ScopedFD fd(HANDLE_EINTR(open("/proc/self/maps", O_RDONLY)));
+  base::ScopedFD fd(HANDLE_EINTR(open(kProcSelfMapsPath, O_RDONLY)));
   if (!fd.is_valid()) {
-    DPLOG(ERROR) << "Couldn't open /proc/self/maps";
+    DPLOG(ERROR) << "Couldn't open " << kProcSelfMapsPath;
     return false;
   }
   proc_maps->clear();
@@ -57,7 +63,7 @@ bool ReadProcMaps(std::string* proc_maps) {
 
     ssize_t bytes_read = HANDLE_EINTR(read(fd.get(), buffer, kReadSize));
     if (bytes_read < 0) {
-      DPLOG(ERROR) << "Couldn't read /proc/self/maps";
+      DPLOG(ERROR) << "Couldn't read " << kProcSelfMapsPath;
       proc_maps->clear();
       return false;
     }
@@ -68,6 +74,7 @@ bool ReadProcMaps(std::string* proc_maps) {
     if (bytes_read == 0)
       break;
 
+#if !defined(OS_BSD)
     // The gate VMA is handled as a special case after seq_file has finished
     // iterating through all entries in the virtual memory table.
     //
@@ -78,6 +85,7 @@ bool ReadProcMaps(std::string* proc_maps) {
     // Avoid this by searching for the gate VMA and breaking early.
     if (ContainsGateVMA(proc_maps, pos))
       break;
+#endif
   }
 
   return true;
@@ -105,11 +113,32 @@ bool ParseProcMaps(const std::string& input,
 
     MappedMemoryRegion region;
     const char* line = lines[i].c_str();
-    char permissions[5] = {'\0'};  // Ensure NUL-terminated string.
+    char permissions[6] = {'\0'};  // Ensure NUL-terminated string.
+    int path_index = 0;
+
+#if defined(OS_BSD)
+    if (lines[i].empty())
+      continue;
+
+    char cow;
+
+    // Format:
+    //
+    // start    end      resident private_resident obj                perms ref_count shadow_count flags  cow needs_copy type  fullpath cred ruid
+    // 0x200000 0x202000 2        6                0xfffff80005be9000 r--   3         1            0x1000 COW NC         vnode /bin/cat NCH  -1
+    //
+    if (sscanf(line, "%" SCNxPTR " %" SCNxPTR " %*ld %*ld %*[^ ] %5[^ ] %*d %*d %*x %c%*s %*s %*s %n",
+	       &region.start, &region.end, permissions, &cow, &path_index) < 4) {
+      DPLOG(WARNING) << "sscanf failed for line: " << line;
+      return false;
+    }
+
+    const char* fullpath = line + path_index;
+    const char* cred     = strchr(fullpath, ' ');
+#else
     uint8_t dev_major = 0;
     uint8_t dev_minor = 0;
     long inode = 0;
-    int path_index = 0;
 
     // Sample format from man 5 proc:
     //
@@ -125,6 +154,7 @@ bool ParseProcMaps(const std::string& input,
       DPLOG(WARNING) << "sscanf failed for line: " << line;
       return false;
     }
+#endif
 
     region.permissions = 0;
 
@@ -143,14 +173,31 @@ bool ParseProcMaps(const std::string& input,
     else if (permissions[2] != '-')
       return false;
 
+#if defined(OS_BSD)
+    if (cow == 'C') {
+      region.permissions |= MappedMemoryRegion::PRIVATE;
+    } else if (cow != 'N') {
+      DPLOG(WARNING) << "unknown value for COW in line " << line << ": " << cow;
+      return false;
+    }
+#else
     if (permissions[3] == 'p')
       region.permissions |= MappedMemoryRegion::PRIVATE;
     else if (permissions[3] != 's' && permissions[3] != 'S')  // Shared memory.
       return false;
+#endif
 
     // Pushing then assigning saves us a string copy.
     regions.push_back(region);
+#if defined(OS_BSD)
+    if (cred != nullptr) {
+      regions.back().path.assign(line + path_index, cred - fullpath);
+    } else {
+      regions.back().path.assign(line + path_index);
+    }
+#else
     regions.back().path.assign(line + path_index);
+#endif
   }
 
   regions_out->swap(regions);
