• R/O
  • HTTP
  • SSH
  • HTTPS

提交

標籤
無標籤

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

GNU Binutils with patches for OS216


Commit MetaInfo

修訂25d36f4a5b8edebbef03fb3c45d48259df480c6d (tree)
時間2020-06-16 21:58:32
作者Luis Machado <luis.machado@lina...>
CommiterLuis Machado

Log Message

Refactor parsing of /proc/<pid>/smaps

The Linux kernel exposes the information about MTE-protected pages via the
proc filesystem, more specifically through the smaps file.

What we're looking for is a mapping with the 'mt' flag, which tells us that
mapping was created with a PROT_MTE flag and, thus, is capable of using memory
tagging.

We already parse that file for other purposes (core file
generation/filtering), so this patch refactors the code to make the parsing
of the smaps file reusable for memory tagging.

The function linux_address_in_memtag_page uses the refactored code to allow
querying for memory tag support in a particular address, and it gets used in the
next patch.

gdb/ChangeLog:

YYYY-MM-DD Luis Machado <luis.machado@linaro.org>

* linux-tdep.c (struct smaps_vmflags) <memory_tagging>: New flag
bit.
(struct smaps_data): New struct.
(decode_vmflags): Handle the 'mt' flag.
(parse_smaps_data): New function, refactored from
linux_find_memory_regions_full.
(linux_address_in_memtag_page): New function.
(linux_find_memory_regions_full): Refactor into parse_smaps_data.
* linux-tdep.h (linux_address_in_memtag_page): New prototype.

Change Summary

差異

--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -86,8 +86,33 @@ struct smaps_vmflags
8686 /* Is this a MAP_SHARED mapping (VM_SHARED, "sh"). */
8787
8888 unsigned int shared_mapping : 1;
89+
90+ /* Memory map has memory tagging enabled. */
91+
92+ unsigned int memory_tagging : 1;
8993 };
9094
95+/* Data structure that holds the information contained in the
96+ /proc/<pid>/smaps file. */
97+
98+struct smaps_data
99+{
100+ ULONGEST start_address;
101+ ULONGEST end_address;
102+ std::string filename;
103+ struct smaps_vmflags vmflags;
104+ bool read;
105+ bool write;
106+ bool exec;
107+ bool priv;
108+ bool has_anonymous;
109+ bool mapping_anon_p;
110+ bool mapping_file_p;
111+
112+ ULONGEST inode;
113+ ULONGEST offset;
114+};
115+
91116 /* Whether to take the /proc/PID/coredump_filter into account when
92117 generating a corefile. */
93118
@@ -472,6 +497,8 @@ decode_vmflags (char *p, struct smaps_vmflags *v)
472497 v->exclude_coredump = 1;
473498 else if (strcmp (s, "sh") == 0)
474499 v->shared_mapping = 1;
500+ else if (strcmp (s, "mt") == 0)
501+ v->memory_tagging = 1;
475502 }
476503 }
477504
@@ -1172,6 +1199,185 @@ typedef int linux_find_memory_region_ftype (ULONGEST vaddr, ULONGEST size,
11721199 const char *filename,
11731200 void *data);
11741201
1202+/* Helper function to parse the contents of /proc/<pid>/smaps into a data
1203+ structure, for easy access.
1204+
1205+ DATA is the contents of the smaps file. The parsed contents are stored
1206+ into the SMAPS vector. */
1207+
1208+static int
1209+parse_smaps_data (const char *data,
1210+ std::vector<struct smaps_data> &smaps,
1211+ const char *mapsfilename)
1212+{
1213+ char *line, *t;
1214+
1215+ gdb_assert (data != nullptr);
1216+
1217+ smaps.clear ();
1218+
1219+ line = strtok_r ((char *) data, "\n", &t);
1220+
1221+ while (line != NULL)
1222+ {
1223+ ULONGEST addr, endaddr, offset, inode;
1224+ const char *permissions, *device, *filename;
1225+ struct smaps_vmflags v;
1226+ size_t permissions_len, device_len;
1227+ int read, write, exec, priv;
1228+ int has_anonymous = 0;
1229+ int mapping_anon_p;
1230+ int mapping_file_p;
1231+
1232+ memset (&v, 0, sizeof (v));
1233+ read_mapping (line, &addr, &endaddr, &permissions, &permissions_len,
1234+ &offset, &device, &device_len, &inode, &filename);
1235+ mapping_anon_p = mapping_is_anonymous_p (filename);
1236+ /* If the mapping is not anonymous, then we can consider it
1237+ to be file-backed. These two states (anonymous or
1238+ file-backed) seem to be exclusive, but they can actually
1239+ coexist. For example, if a file-backed mapping has
1240+ "Anonymous:" pages (see more below), then the Linux
1241+ kernel will dump this mapping when the user specified
1242+ that she only wants anonymous mappings in the corefile
1243+ (*even* when she explicitly disabled the dumping of
1244+ file-backed mappings). */
1245+ mapping_file_p = !mapping_anon_p;
1246+
1247+ /* Decode permissions. */
1248+ read = (memchr (permissions, 'r', permissions_len) != 0);
1249+ write = (memchr (permissions, 'w', permissions_len) != 0);
1250+ exec = (memchr (permissions, 'x', permissions_len) != 0);
1251+ /* 'private' here actually means VM_MAYSHARE, and not
1252+ VM_SHARED. In order to know if a mapping is really
1253+ private or not, we must check the flag "sh" in the
1254+ VmFlags field. This is done by decode_vmflags. However,
1255+ if we are using a Linux kernel released before the commit
1256+ 834f82e2aa9a8ede94b17b656329f850c1471514 (3.10), we will
1257+ not have the VmFlags there. In this case, there is
1258+ really no way to know if we are dealing with VM_SHARED,
1259+ so we just assume that VM_MAYSHARE is enough. */
1260+ priv = memchr (permissions, 'p', permissions_len) != 0;
1261+
1262+ /* Try to detect if region should be dumped by parsing smaps
1263+ counters. */
1264+ for (line = strtok_r (NULL, "\n", &t);
1265+ line != NULL && line[0] >= 'A' && line[0] <= 'Z';
1266+ line = strtok_r (NULL, "\n", &t))
1267+ {
1268+ char keyword[64 + 1];
1269+
1270+ if (sscanf (line, "%64s", keyword) != 1)
1271+ {
1272+ warning (_("Error parsing {s,}maps file '%s'"), mapsfilename);
1273+ break;
1274+ }
1275+
1276+ if (strcmp (keyword, "Anonymous:") == 0)
1277+ {
1278+ /* Older Linux kernels did not support the
1279+ "Anonymous:" counter. Check it here. */
1280+ has_anonymous = 1;
1281+ }
1282+ else if (strcmp (keyword, "VmFlags:") == 0)
1283+ decode_vmflags (line, &v);
1284+
1285+ if (strcmp (keyword, "AnonHugePages:") == 0
1286+ || strcmp (keyword, "Anonymous:") == 0)
1287+ {
1288+ unsigned long number;
1289+
1290+ if (sscanf (line, "%*s%lu", &number) != 1)
1291+ {
1292+ warning (_("Error parsing {s,}maps file '%s' number"),
1293+ mapsfilename);
1294+ break;
1295+ }
1296+ if (number > 0)
1297+ {
1298+ /* Even if we are dealing with a file-backed
1299+ mapping, if it contains anonymous pages we
1300+ consider it to be *also* an anonymous
1301+ mapping, because this is what the Linux
1302+ kernel does:
1303+
1304+ // Dump segments that have been written to.
1305+ if (vma->anon_vma && FILTER(ANON_PRIVATE))
1306+ goto whole;
1307+
1308+ Note that if the mapping is already marked as
1309+ file-backed (i.e., mapping_file_p is
1310+ non-zero), then this is a special case, and
1311+ this mapping will be dumped either when the
1312+ user wants to dump file-backed *or* anonymous
1313+ mappings. */
1314+ mapping_anon_p = 1;
1315+ }
1316+ }
1317+ }
1318+ /* Save the smaps entry to the vector. */
1319+ struct smaps_data map;
1320+ std::string fname (filename);
1321+
1322+ map.start_address = addr;
1323+ map.end_address = endaddr;
1324+ map.filename = fname;
1325+ map.vmflags = v;
1326+ map.read = read? true : false;
1327+ map.write = write? true : false;
1328+ map.exec = exec? true : false;
1329+ map.priv = priv? true : false;
1330+ map.has_anonymous = has_anonymous;
1331+ map.mapping_anon_p = mapping_anon_p? true : false;
1332+ map.mapping_file_p = mapping_file_p? true : false;
1333+ map.offset = offset;
1334+ map.inode = inode;
1335+
1336+ smaps.emplace_back (map);
1337+ }
1338+
1339+ return 0;
1340+}
1341+
1342+/* See linux-tdep.h. */
1343+
1344+bool
1345+linux_address_in_memtag_page (CORE_ADDR address)
1346+{
1347+ if (current_inferior ()->fake_pid_p)
1348+ return false;
1349+
1350+ pid_t pid = current_inferior ()->pid;
1351+
1352+ std::string smaps_file = string_printf ("/proc/%d/smaps", pid);
1353+
1354+ gdb::unique_xmalloc_ptr<char> data
1355+ = target_fileio_read_stralloc (NULL, smaps_file.c_str ());
1356+
1357+ if (data == nullptr)
1358+ return false;
1359+
1360+ std::vector<struct smaps_data> smaps;
1361+
1362+ /* Parse the contents of smaps into a vector. */
1363+ parse_smaps_data (data.get (), smaps, smaps_file.c_str ());
1364+
1365+ if (!smaps.empty ())
1366+ {
1367+ for (struct smaps_data map : smaps)
1368+ {
1369+ /* Is the address within [start_address, end_address) in a page
1370+ mapped with memory tagging? */
1371+ if (address >= map.start_address
1372+ && address < map.end_address
1373+ && map.vmflags.memory_tagging)
1374+ return true;
1375+ }
1376+ }
1377+
1378+ return false;
1379+}
1380+
11751381 /* List memory regions in the inferior for a corefile. */
11761382
11771383 static int
@@ -1179,8 +1385,7 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
11791385 linux_find_memory_region_ftype *func,
11801386 void *obfd)
11811387 {
1182- char mapsfilename[100];
1183- char coredumpfilter_name[100];
1388+ std::string coredumpfilter_name;
11841389 pid_t pid;
11851390 /* Default dump behavior of coredump_filter (0x33), according to
11861391 Documentation/filesystems/proc.txt from the Linux kernel
@@ -1198,10 +1403,9 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
11981403
11991404 if (use_coredump_filter)
12001405 {
1201- xsnprintf (coredumpfilter_name, sizeof (coredumpfilter_name),
1202- "/proc/%d/coredump_filter", pid);
1406+ coredumpfilter_name = string_printf ("/proc/%d/coredump_filter", pid);
12031407 gdb::unique_xmalloc_ptr<char> coredumpfilterdata
1204- = target_fileio_read_stralloc (NULL, coredumpfilter_name);
1408+ = target_fileio_read_stralloc (NULL, coredumpfilter_name.c_str ());
12051409 if (coredumpfilterdata != NULL)
12061410 {
12071411 unsigned int flags;
@@ -1211,124 +1415,37 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
12111415 }
12121416 }
12131417
1214- xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/smaps", pid);
1418+ std::string mapsfilename = string_printf ("/proc/%d/smaps", pid);
12151419 gdb::unique_xmalloc_ptr<char> data
1216- = target_fileio_read_stralloc (NULL, mapsfilename);
1420+ = target_fileio_read_stralloc (NULL, mapsfilename.c_str ());
12171421 if (data == NULL)
12181422 {
12191423 /* Older Linux kernels did not support /proc/PID/smaps. */
1220- xsnprintf (mapsfilename, sizeof mapsfilename, "/proc/%d/maps", pid);
1221- data = target_fileio_read_stralloc (NULL, mapsfilename);
1424+ mapsfilename = string_printf ("/proc/%d/maps", pid);
1425+ data = target_fileio_read_stralloc (NULL, mapsfilename.c_str ());
12221426 }
12231427
1224- if (data != NULL)
1225- {
1226- char *line, *t;
1227-
1228- line = strtok_r (data.get (), "\n", &t);
1229- while (line != NULL)
1230- {
1231- ULONGEST addr, endaddr, offset, inode;
1232- const char *permissions, *device, *filename;
1233- struct smaps_vmflags v;
1234- size_t permissions_len, device_len;
1235- int read, write, exec, priv;
1236- int has_anonymous = 0;
1237- int should_dump_p = 0;
1238- int mapping_anon_p;
1239- int mapping_file_p;
1240-
1241- memset (&v, 0, sizeof (v));
1242- read_mapping (line, &addr, &endaddr, &permissions, &permissions_len,
1243- &offset, &device, &device_len, &inode, &filename);
1244- mapping_anon_p = mapping_is_anonymous_p (filename);
1245- /* If the mapping is not anonymous, then we can consider it
1246- to be file-backed. These two states (anonymous or
1247- file-backed) seem to be exclusive, but they can actually
1248- coexist. For example, if a file-backed mapping has
1249- "Anonymous:" pages (see more below), then the Linux
1250- kernel will dump this mapping when the user specified
1251- that she only wants anonymous mappings in the corefile
1252- (*even* when she explicitly disabled the dumping of
1253- file-backed mappings). */
1254- mapping_file_p = !mapping_anon_p;
1255-
1256- /* Decode permissions. */
1257- read = (memchr (permissions, 'r', permissions_len) != 0);
1258- write = (memchr (permissions, 'w', permissions_len) != 0);
1259- exec = (memchr (permissions, 'x', permissions_len) != 0);
1260- /* 'private' here actually means VM_MAYSHARE, and not
1261- VM_SHARED. In order to know if a mapping is really
1262- private or not, we must check the flag "sh" in the
1263- VmFlags field. This is done by decode_vmflags. However,
1264- if we are using a Linux kernel released before the commit
1265- 834f82e2aa9a8ede94b17b656329f850c1471514 (3.10), we will
1266- not have the VmFlags there. In this case, there is
1267- really no way to know if we are dealing with VM_SHARED,
1268- so we just assume that VM_MAYSHARE is enough. */
1269- priv = memchr (permissions, 'p', permissions_len) != 0;
1270-
1271- /* Try to detect if region should be dumped by parsing smaps
1272- counters. */
1273- for (line = strtok_r (NULL, "\n", &t);
1274- line != NULL && line[0] >= 'A' && line[0] <= 'Z';
1275- line = strtok_r (NULL, "\n", &t))
1276- {
1277- char keyword[64 + 1];
1428+ if (data == nullptr)
1429+ return 1;
12781430
1279- if (sscanf (line, "%64s", keyword) != 1)
1280- {
1281- warning (_("Error parsing {s,}maps file '%s'"), mapsfilename);
1282- break;
1283- }
1431+ std::vector<struct smaps_data> smaps;
12841432
1285- if (strcmp (keyword, "Anonymous:") == 0)
1286- {
1287- /* Older Linux kernels did not support the
1288- "Anonymous:" counter. Check it here. */
1289- has_anonymous = 1;
1290- }
1291- else if (strcmp (keyword, "VmFlags:") == 0)
1292- decode_vmflags (line, &v);
1433+ /* Parse the contents of smaps into a vector. */
1434+ parse_smaps_data (data.get (), smaps, mapsfilename.c_str ());
12931435
1294- if (strcmp (keyword, "AnonHugePages:") == 0
1295- || strcmp (keyword, "Anonymous:") == 0)
1296- {
1297- unsigned long number;
1298-
1299- if (sscanf (line, "%*s%lu", &number) != 1)
1300- {
1301- warning (_("Error parsing {s,}maps file '%s' number"),
1302- mapsfilename);
1303- break;
1304- }
1305- if (number > 0)
1306- {
1307- /* Even if we are dealing with a file-backed
1308- mapping, if it contains anonymous pages we
1309- consider it to be *also* an anonymous
1310- mapping, because this is what the Linux
1311- kernel does:
1312-
1313- // Dump segments that have been written to.
1314- if (vma->anon_vma && FILTER(ANON_PRIVATE))
1315- goto whole;
1316-
1317- Note that if the mapping is already marked as
1318- file-backed (i.e., mapping_file_p is
1319- non-zero), then this is a special case, and
1320- this mapping will be dumped either when the
1321- user wants to dump file-backed *or* anonymous
1322- mappings. */
1323- mapping_anon_p = 1;
1324- }
1325- }
1326- }
1436+ if (!smaps.empty ())
1437+ {
1438+ for (struct smaps_data map : smaps)
1439+ {
1440+ int should_dump_p = 0;
13271441
1328- if (has_anonymous)
1329- should_dump_p = dump_mapping_p (filterflags, &v, priv,
1330- mapping_anon_p, mapping_file_p,
1331- filename, addr, offset);
1442+ if (map.has_anonymous)
1443+ should_dump_p = dump_mapping_p (filterflags, &map.vmflags, map.priv,
1444+ map.mapping_anon_p,
1445+ map.mapping_file_p,
1446+ map.filename.c_str (),
1447+ map.start_address,
1448+ map.offset);
13321449 else
13331450 {
13341451 /* Older Linux kernels did not support the "Anonymous:" counter.
@@ -1338,16 +1455,15 @@ linux_find_memory_regions_full (struct gdbarch *gdbarch,
13381455
13391456 /* Invoke the callback function to create the corefile segment. */
13401457 if (should_dump_p)
1341- func (addr, endaddr - addr, offset, inode,
1342- read, write, exec, 1, /* MODIFIED is true because we
1343- want to dump the mapping. */
1344- filename, obfd);
1458+ func (map.start_address, map.end_address - map.start_address,
1459+ map.offset, map.inode, map.read, map.write, map.exec,
1460+ 1, /* MODIFIED is true because we want to dump
1461+ the mapping. */
1462+ map.filename.c_str (), obfd);
13451463 }
1346-
1347- return 0;
13481464 }
13491465
1350- return 1;
1466+ return 0;
13511467 }
13521468
13531469 /* A structure for passing information through
--- a/gdb/linux-tdep.h
+++ b/gdb/linux-tdep.h
@@ -41,6 +41,10 @@ DEF_ENUM_FLAGS_TYPE (enum linux_siginfo_extra_field_values,
4141 struct type *linux_get_siginfo_type_with_fields (struct gdbarch *gdbarch,
4242 linux_siginfo_extra_fields);
4343
44+ /* Return true if ADDRESS is within the boundaries of a page mapped with
45+ memory tagging protection. */
46+bool linux_address_in_memtag_page (CORE_ADDR address);
47+
4448 typedef char *(*linux_collect_thread_registers_ftype) (const struct regcache *,
4549 ptid_t,
4650 bfd *, char *, int *,