1eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// found in the LICENSE file.
4eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
5eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#ifndef BASE_DEBUG_PROC_MAPS_LINUX_H_
6eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#define BASE_DEBUG_PROC_MAPS_LINUX_H_
7eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
8eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <string>
9eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <vector>
10eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
11eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/base_export.h"
12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/basictypes.h"
13eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
14eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace base {
15eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace debug {
16eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
17eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Describes a region of mapped memory and the path of the file mapped.
18eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochstruct MappedMemoryRegion {
19eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  enum Permission {
20eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    READ = 1 << 0,
21eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    WRITE = 1 << 1,
22eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    EXECUTE = 1 << 2,
23eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    PRIVATE = 1 << 3,  // If set, region is private, otherwise it is shared.
24eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  };
25eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
26eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // The address range [start,end) of mapped memory.
27eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  uintptr_t start;
28eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  uintptr_t end;
29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
30eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Byte offset into |path| of the range mapped into memory.
31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  unsigned long long offset;
32eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
33eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Bitmask of read/write/execute/private/shared permissions.
34eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  uint8 permissions;
35eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Name of the file mapped into memory.
37eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  //
38eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // NOTE: path names aren't guaranteed to point at valid files. For example,
39eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // "[heap]" and "[stack]" are used to represent the location of the process'
40eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // heap and stack, respectively.
41eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  std::string path;
42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch};
43eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
44eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Reads the data from /proc/self/maps and stores the result in |proc_maps|.
45eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Returns true if successful, false otherwise.
4658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)//
4758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// There is *NO* guarantee that the resulting contents will be free of
4858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// duplicates or even contain valid entries by time the method returns.
4958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)//
5058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)//
5158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// THE GORY DETAILS
5258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)//
5358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// Did you know it's next-to-impossible to atomically read the whole contents
5458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// of /proc/<pid>/maps? You would think that if we passed in a large-enough
5558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// buffer to read() that It Should Just Work(tm), but sadly that's not the case.
5658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)//
5758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// Linux's procfs uses seq_file [1] for handling iteration, text formatting,
5858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// and dealing with resulting data that is larger than the size of a page. That
5958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// last bit is especially important because it means that seq_file will never
6058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// return more than the size of a page in a single call to read().
6158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)//
6258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// Unfortunately for a program like Chrome the size of /proc/self/maps is
6358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// larger than the size of page so we're forced to call read() multiple times.
6458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// If the virtual memory table changed in any way between calls to read() (e.g.,
6558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// a different thread calling mprotect()), it can make seq_file generate
6658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// duplicate entries or skip entries.
6758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)//
6858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// Even if seq_file was changed to keep flushing the contents of its page-sized
6958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// buffer to the usermode buffer inside a single call to read(), it has to
7058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// release its lock on the virtual memory table to handle page faults while
7158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// copying data to usermode. This puts us in the same situation where the table
7258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// can change while we're copying data.
7358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)//
7458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// Alternatives such as fork()-and-suspend-the-parent-while-child-reads were
7558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// attempted, but they present more subtle problems than it's worth. Depending
7658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// on your use case your best bet may be to read /proc/<pid>/maps prior to
7758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// starting other threads.
7858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)//
7958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)// [1] http://kernelnewbies.org/Documents/SeqFileHowTo
80eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochBASE_EXPORT bool ReadProcMaps(std::string* proc_maps);
81eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
82eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Parses /proc/<pid>/maps input data and stores in |regions|. Returns true
83eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// and updates |regions| if and only if all of |input| was successfully parsed.
84eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochBASE_EXPORT bool ParseProcMaps(const std::string& input,
85eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                               std::vector<MappedMemoryRegion>* regions);
86eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
87eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}  // namespace debug
88eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}  // namespace base
89eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
90eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#endif  // BASE_DEBUG_PROC_MAPS_LINUX_H_
91