/ src / processor / proc_maps_linux_unittest.cc
proc_maps_linux_unittest.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  #ifdef HAVE_CONFIG_H
  6  #include <config.h>  // Must come first
  7  #endif
  8  
  9  #include "breakpad_googletest_includes.h"
 10  #include "common/using_std_string.h"
 11  #include "google_breakpad/processor/proc_maps_linux.h"
 12  
 13  namespace {
 14  
 15  TEST(ProcMapsTest, Empty) {
 16    std::vector<google_breakpad::MappedMemoryRegion> regions;
 17    EXPECT_TRUE(ParseProcMaps("", &regions));
 18    EXPECT_EQ(0u, regions.size());
 19  }
 20  
 21  TEST(ProcMapsTest, NoSpaces) {
 22    static const char kNoSpaces[] =
 23        "00400000-0040b000 r-xp 00002200 fc:00 794418 /bin/cat\n";
 24  
 25    std::vector<google_breakpad::MappedMemoryRegion> regions;
 26    ASSERT_TRUE(ParseProcMaps(kNoSpaces, &regions));
 27    ASSERT_EQ(1u, regions.size());
 28  
 29    EXPECT_EQ(0x00400000u, regions[0].start);
 30    EXPECT_EQ(0x0040b000u, regions[0].end);
 31    EXPECT_EQ(0x00002200u, regions[0].offset);
 32    EXPECT_EQ("/bin/cat", regions[0].path);
 33  }
 34  
 35  TEST(ProcMapsTest, Spaces) {
 36    static const char kSpaces[] =
 37        "00400000-0040b000 r-xp 00002200 fc:00 794418 /bin/space cat\n";
 38  
 39    std::vector<google_breakpad::MappedMemoryRegion> regions;
 40    ASSERT_TRUE(ParseProcMaps(kSpaces, &regions));
 41    ASSERT_EQ(1u, regions.size());
 42  
 43    EXPECT_EQ(0x00400000u, regions[0].start);
 44    EXPECT_EQ(0x0040b000u, regions[0].end);
 45    EXPECT_EQ(0x00002200u, regions[0].offset);
 46    EXPECT_EQ("/bin/space cat", regions[0].path);
 47  }
 48  
 49  TEST(ProcMapsTest, NoNewline) {
 50    static const char kNoSpaces[] =
 51        "00400000-0040b000 r-xp 00002200 fc:00 794418 /bin/cat";
 52  
 53    std::vector<google_breakpad::MappedMemoryRegion> regions;
 54    ASSERT_FALSE(ParseProcMaps(kNoSpaces, &regions));
 55  }
 56  
 57  TEST(ProcMapsTest, NoPath) {
 58    static const char kNoPath[] =
 59        "00400000-0040b000 rw-p 00000000 00:00 0 \n";
 60  
 61    std::vector<google_breakpad::MappedMemoryRegion> regions;
 62    ASSERT_TRUE(ParseProcMaps(kNoPath, &regions));
 63    ASSERT_EQ(1u, regions.size());
 64  
 65    EXPECT_EQ(0x00400000u, regions[0].start);
 66    EXPECT_EQ(0x0040b000u, regions[0].end);
 67    EXPECT_EQ(0x00000000u, regions[0].offset);
 68    EXPECT_EQ("", regions[0].path);
 69  }
 70  
 71  TEST(ProcMapsTest, Heap) {
 72    static const char kHeap[] =
 73        "022ac000-022cd000 rw-p 00000000 00:00 0 [heap]\n";
 74  
 75    std::vector<google_breakpad::MappedMemoryRegion> regions;
 76    ASSERT_TRUE(ParseProcMaps(kHeap, &regions));
 77    ASSERT_EQ(1u, regions.size());
 78  
 79    EXPECT_EQ(0x022ac000u, regions[0].start);
 80    EXPECT_EQ(0x022cd000u, regions[0].end);
 81    EXPECT_EQ(0x00000000u, regions[0].offset);
 82    EXPECT_EQ("[heap]", regions[0].path);
 83  }
 84  
 85  #if defined(ARCH_CPU_32_BITS)
 86  TEST(ProcMapsTest, Stack32) {
 87    static const char kStack[] =
 88        "beb04000-beb25000 rw-p 00000000 00:00 0 [stack]\n";
 89  
 90    std::vector<google_breakpad::MappedMemoryRegion> regions;
 91    ASSERT_TRUE(ParseProcMaps(kStack, &regions));
 92    ASSERT_EQ(1u, regions.size());
 93  
 94    EXPECT_EQ(0xbeb04000u, regions[0].start);
 95    EXPECT_EQ(0xbeb25000u, regions[0].end);
 96    EXPECT_EQ(0x00000000u, regions[0].offset);
 97    EXPECT_EQ("[stack]", regions[0].path);
 98  }
 99  #elif defined(ARCH_CPU_64_BITS)
100  TEST(ProcMapsTest, Stack64) {
101    static const char kStack[] =
102        "7fff69c5b000-7fff69c7d000 rw-p 00000000 00:00 0 [stack]\n";
103  
104    std::vector<google_breakpad::MappedMemoryRegion> regions;
105    ASSERT_TRUE(ParseProcMaps(kStack, &regions));
106    ASSERT_EQ(1u, regions.size());
107  
108    EXPECT_EQ(0x7fff69c5b000u, regions[0].start);
109    EXPECT_EQ(0x7fff69c7d000u, regions[0].end);
110    EXPECT_EQ(0x00000000u, regions[0].offset);
111    EXPECT_EQ("[stack]", regions[0].path);
112  }
113  #endif
114  
115  TEST(ProcMapsTest, Multiple) {
116    static const char kMultiple[] =
117        "00400000-0040b000 r-xp 00000000 fc:00 794418 /bin/cat\n"
118        "0060a000-0060b000 r--p 0000a000 fc:00 794418 /bin/cat\n"
119        "0060b000-0060c000 rw-p 0000b000 fc:00 794418 /bin/cat\n";
120  
121    std::vector<google_breakpad::MappedMemoryRegion> regions;
122    ASSERT_TRUE(ParseProcMaps(kMultiple, &regions));
123    ASSERT_EQ(3u, regions.size());
124  
125    EXPECT_EQ(0x00400000u, regions[0].start);
126    EXPECT_EQ(0x0040b000u, regions[0].end);
127    EXPECT_EQ(0x00000000u, regions[0].offset);
128    EXPECT_EQ("/bin/cat", regions[0].path);
129  
130    EXPECT_EQ(0x0060a000u, regions[1].start);
131    EXPECT_EQ(0x0060b000u, regions[1].end);
132    EXPECT_EQ(0x0000a000u, regions[1].offset);
133    EXPECT_EQ("/bin/cat", regions[1].path);
134  
135    EXPECT_EQ(0x0060b000u, regions[2].start);
136    EXPECT_EQ(0x0060c000u, regions[2].end);
137    EXPECT_EQ(0x0000b000u, regions[2].offset);
138    EXPECT_EQ("/bin/cat", regions[2].path);
139  }
140  
141  TEST(ProcMapsTest, Permissions) {
142    static struct {
143      const char* input;
144      uint8_t permissions;
145    } kTestCases[] = {
146      {"00400000-0040b000 ---s 00000000 fc:00 794418 /bin/cat\n", 0},
147      {"00400000-0040b000 ---S 00000000 fc:00 794418 /bin/cat\n", 0},
148      {"00400000-0040b000 r--s 00000000 fc:00 794418 /bin/cat\n",
149        google_breakpad::MappedMemoryRegion::READ},
150      {"00400000-0040b000 -w-s 00000000 fc:00 794418 /bin/cat\n",
151        google_breakpad::MappedMemoryRegion::WRITE},
152      {"00400000-0040b000 --xs 00000000 fc:00 794418 /bin/cat\n",
153        google_breakpad::MappedMemoryRegion::EXECUTE},
154      {"00400000-0040b000 rwxs 00000000 fc:00 794418 /bin/cat\n",
155        google_breakpad::MappedMemoryRegion::READ
156          | google_breakpad::MappedMemoryRegion::WRITE
157          | google_breakpad::MappedMemoryRegion::EXECUTE},
158      {"00400000-0040b000 ---p 00000000 fc:00 794418 /bin/cat\n",
159        google_breakpad::MappedMemoryRegion::PRIVATE},
160      {"00400000-0040b000 r--p 00000000 fc:00 794418 /bin/cat\n",
161        google_breakpad::MappedMemoryRegion::READ
162          | google_breakpad::MappedMemoryRegion::PRIVATE},
163      {"00400000-0040b000 -w-p 00000000 fc:00 794418 /bin/cat\n",
164        google_breakpad::MappedMemoryRegion::WRITE
165          | google_breakpad::MappedMemoryRegion::PRIVATE},
166      {"00400000-0040b000 --xp 00000000 fc:00 794418 /bin/cat\n",
167        google_breakpad::MappedMemoryRegion::EXECUTE
168          | google_breakpad::MappedMemoryRegion::PRIVATE},
169      {"00400000-0040b000 rwxp 00000000 fc:00 794418 /bin/cat\n",
170        google_breakpad::MappedMemoryRegion::READ
171          | google_breakpad::MappedMemoryRegion::WRITE
172          | google_breakpad::MappedMemoryRegion::EXECUTE
173          | google_breakpad::MappedMemoryRegion::PRIVATE},
174    };
175  
176    for (size_t i = 0; i < sizeof(kTestCases) / sizeof(kTestCases[0]); ++i) {
177      std::vector<google_breakpad::MappedMemoryRegion> regions;
178      EXPECT_TRUE(ParseProcMaps(kTestCases[i].input, &regions));
179      EXPECT_EQ(1u, regions.size());
180      if (regions.empty())
181        continue;
182      EXPECT_EQ(kTestCases[i].permissions, regions[0].permissions);
183    }
184  }
185  
186  TEST(ProcMapsTest, MissingFields) {
187    static const char* kTestCases[] = {
188      "00400000\n",                               // Missing end + beyond.
189      "00400000-0040b000\n",                      // Missing perms + beyond.
190      "00400000-0040b000 r-xp\n",                 // Missing offset + beyond.
191      "00400000-0040b000 r-xp 00000000\n",        // Missing device + beyond.
192      "00400000-0040b000 r-xp 00000000 fc:00\n",  // Missing inode + beyond.
193      "00400000-0040b000 00000000 fc:00 794418 /bin/cat\n",  // Missing perms.
194      "00400000-0040b000 r-xp fc:00 794418 /bin/cat\n",      // Missing offset.
195      "00400000-0040b000 r-xp 00000000 fc:00 /bin/cat\n",    // Missing inode.
196      "00400000 r-xp 00000000 fc:00 794418 /bin/cat\n",      // Missing end.
197      "-0040b000 r-xp 00000000 fc:00 794418 /bin/cat\n",     // Missing start.
198      "00400000-0040b000 r-xp 00000000 794418 /bin/cat\n",   // Missing device.
199    };
200  
201    for (size_t i = 0; i < sizeof(kTestCases) / sizeof(kTestCases[0]); ++i) {
202      std::vector<google_breakpad::MappedMemoryRegion> regions;
203      EXPECT_FALSE(ParseProcMaps(kTestCases[i], &regions));
204    }
205  }
206  
207  TEST(ProcMapsTest, InvalidInput) {
208    static const char* kTestCases[] = {
209      "thisisal-0040b000 rwxp 00000000 fc:00 794418 /bin/cat\n",
210      "0040000d-linvalid rwxp 00000000 fc:00 794418 /bin/cat\n",
211      "00400000-0040b000 inpu 00000000 fc:00 794418 /bin/cat\n",
212      "00400000-0040b000 rwxp tforproc fc:00 794418 /bin/cat\n",
213      "00400000-0040b000 rwxp 00000000 ma:ps 794418 /bin/cat\n",
214      "00400000-0040b000 rwxp 00000000 fc:00 parse! /bin/cat\n",
215    };
216  
217    for (size_t i = 0; i < sizeof(kTestCases) / sizeof(kTestCases[0]); ++i) {
218      std::vector<google_breakpad::MappedMemoryRegion> regions;
219      EXPECT_FALSE(ParseProcMaps(kTestCases[i], &regions));
220    }
221  }
222  
223  TEST(ProcMapsTest, ParseProcMapsEmptyString) {
224    std::vector<google_breakpad::MappedMemoryRegion> regions;
225    EXPECT_TRUE(ParseProcMaps("", &regions));
226    EXPECT_EQ(0ULL, regions.size());
227  }
228  
229  // Testing a couple of remotely possible weird things in the input:
230  // - Line ending with \r\n or \n\r.
231  // - File name contains quotes.
232  // - File name has whitespaces.
233  TEST(ProcMapsTest, ParseProcMapsWeirdCorrectInput) {
234    std::vector<google_breakpad::MappedMemoryRegion> regions;
235    const string kContents =
236      "00400000-0040b000 r-xp 00000000 fc:00 2106562 "
237        "               /bin/cat\r\n"
238      "7f53b7dad000-7f53b7f62000 r-xp 00000000 fc:00 263011 "
239        "       /lib/x86_64-linux-gnu/libc-2.15.so\n\r"
240      "7f53b816d000-7f53b818f000 r-xp 00000000 fc:00 264284 "
241        "        /lib/x86_64-linux-gnu/ld-2.15.so\n"
242      "7fff9c7ff000-7fff9c800000 r-xp 00000000 00:00 0 "
243        "               \"vd so\"\n"
244      "ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 "
245        "               [vsys call]\n";
246    EXPECT_TRUE(ParseProcMaps(kContents, &regions));
247    EXPECT_EQ(5ULL, regions.size());
248    EXPECT_EQ("/bin/cat", regions[0].path);
249    EXPECT_EQ("/lib/x86_64-linux-gnu/libc-2.15.so", regions[1].path);
250    EXPECT_EQ("/lib/x86_64-linux-gnu/ld-2.15.so", regions[2].path);
251    EXPECT_EQ("\"vd so\"", regions[3].path);
252    EXPECT_EQ("[vsys call]", regions[4].path);
253  }
254  
255  }  // namespace