[DTrace-devel] [PATCH 09/17] libproc: add Pinode_to_map()
Nick Alcock
nick.alcock at oracle.com
Wed Aug 10 22:07:01 UTC 2022
This lets you hand in a (dev, ino) pair and get back the prmap_file_t
entry that corresponds to it. This is useful when dealing with uprobes,
which work on an *inode* basis, not a process basis or even a mapping
basis.
Signed-off-by: Nick Alcock <nick.alcock at oracle.com>
---
include/sys/sol_procfs.h | 6 +--
libproc/Pcontrol.h | 1 +
libproc/Psymtab.c | 83 ++++++++++++++++++++++++++++++++++++----
libproc/libproc.h | 3 ++
4 files changed, 83 insertions(+), 10 deletions(-)
diff --git a/include/sys/sol_procfs.h b/include/sys/sol_procfs.h
index 2f7c6a4eafe5..3ce64e9b3301 100644
--- a/include/sys/sol_procfs.h
+++ b/include/sys/sol_procfs.h
@@ -17,17 +17,17 @@ extern "C" {
#include <sys/types.h>
#include <sys/dtrace_types.h>
#include <sys/procfs_isa.h>
-#include <dt_list.h>
#include <link.h>
/*
* The prmap_file points to all mappings corresponding to a single file, sorted
* by address. prmap_files are hashed by name (including the terminating \0,
- * so anonymous maps are all hashed together).
+ * so anonymous maps are all hashed together) and by dev/inode number.
*/
struct prmap;
typedef struct prmap_file {
- struct prmap_file *prf_next; /* next in hash chain */
+ struct prmap_file *prf_next; /* next in filename hash chain */
+ struct prmap_file *prf_inum_next; /* next in inode hash chain */
char *prf_mapname; /* name in /proc/<pid>/maps */
struct prmap **prf_mappings; /* sorted by address */
size_t prf_num_mappings; /* number of mappings */
diff --git a/libproc/Pcontrol.h b/libproc/Pcontrol.h
index 9c3340d04d54..77d71d98abf0 100644
--- a/libproc/Pcontrol.h
+++ b/libproc/Pcontrol.h
@@ -247,6 +247,7 @@ struct ps_prochandle {
map_info_t *mappings; /* process mappings, sorted by address */
size_t num_mappings; /* number of mappings */
prmap_file_t **map_files; /* hash of mappings by filename */
+ prmap_file_t **map_inum; /* hash of mappings by (dev, inode) */
uint_t num_files; /* number of file elements in file_list */
dt_list_t file_list; /* list of mapped files w/ symbol table info */
auxv_t *auxv; /* the process's aux vector */
diff --git a/libproc/Psymtab.c b/libproc/Psymtab.c
index aca3382bdde5..e03616a5b5c0 100644
--- a/libproc/Psymtab.c
+++ b/libproc/Psymtab.c
@@ -70,6 +70,39 @@ string_hash(const char *key)
return h;
}
+/*
+ * This is Pelle Evensen's NASAM mixer. Since we are only mixing in one value
+ * we don't need anything but a mixing step.
+ */
+
+#define ror(x,y) ((x) >> (y) | (x) << (64 - (y)))
+
+static uint64_t
+nasam_mix(uint64_t h)
+{
+
+ h ^= ror(h, 25) ^ ror(h, 47);
+ h *= 0x9E6C63D0676A9A99UL;
+ h ^= h >> 23 ^ h >> 51;
+ h *= 0x9E6D62D06F6A9A9BUL;
+ h ^= h >> 23 ^ h >> 51;
+
+ return h;
+}
+#undef ror
+
+static ino_t
+dev_inum_hash(dev_t dev, ino_t inum)
+{
+ uint64_t h;
+
+ h = nasam_mix(inum);
+ h += dev;
+ h = nasam_mix(h);
+
+ return (ino_t) h;
+}
+
/*
* Allocation function for a new file_info_t.
*/
@@ -182,6 +215,7 @@ mapping_purge(struct ps_prochandle *P)
}
memset(P->map_files, 0, sizeof(struct prmap_file *) * MAP_HASH_BUCKETS);
+ memset(P->map_inum, 0, sizeof(struct prmap_file *) * MAP_HASH_BUCKETS);
for (i = 0, fptr = dt_list_next(&P->file_list);
i < P->num_files; i++, fptr = dt_list_next(fptr)) {
@@ -208,6 +242,11 @@ Psym_init(struct ps_prochandle *P)
_dprintf("Out of memory initializing map_files hash\n");
return -ENOMEM;
}
+ P->map_inum = calloc(MAP_HASH_BUCKETS, sizeof(struct prmap_file_t *));
+ if (!P->map_inum) {
+ _dprintf("Out of memory initializing map_inum hash\n");
+ return -ENOMEM;
+ }
return 0;
}
@@ -219,6 +258,8 @@ Psym_free(struct ps_prochandle *P)
{
free(P->map_files);
P->map_files = NULL;
+ free(P->map_inum);
+ P->map_inum = NULL;
}
/*
@@ -238,6 +279,25 @@ static prmap_file_t *Pprmap_file_by_name(struct ps_prochandle *P,
return NULL;
}
+/*
+ * Given a process handle, find a corresponding prmap_file by (dev_t, inode
+ * number), or NULL if none.
+ */
+static prmap_file_t *Pprmap_file_by_dev_inum(struct ps_prochandle *P,
+ dev_t dev, ino_t inum)
+{
+ uint_t h = dev_inum_hash(dev, inum) % MAP_HASH_BUCKETS;
+
+ prmap_file_t *prf;
+
+ for (prf = P->map_inum[h]; prf != NULL; prf = prf->prf_inum_next)
+ if (prf->first_segment->pr_inum == inum &&
+ prf->first_segment->pr_dev == dev)
+ return prf;
+
+ return NULL;
+}
+
/*
* Call-back function for librtld_db to iterate through all of its shared
* libraries and determine their load object names and lmids.
@@ -552,9 +612,13 @@ Pupdate_maps(struct ps_prochandle *P)
goto err;
pmptr = mptr->map_pmap;
memset(pmptr, 0, sizeof(struct prmap));
+ pmptr->pr_dev = makedev(major, minor);
+ pmptr->pr_inum = inode;
if ((prf = Pprmap_file_by_name(P, fn)) == NULL) {
- uint_t h = string_hash(fn) % MAP_HASH_BUCKETS;
+ uint_t fn_h = string_hash(fn) % MAP_HASH_BUCKETS;
+ uint_t inum_h = dev_inum_hash(pmptr->pr_dev, pmptr->pr_inum) %
+ MAP_HASH_BUCKETS;
if ((prf = malloc(sizeof(struct prmap_file))) == NULL) {
free(mptr->map_pmap);
@@ -563,10 +627,11 @@ Pupdate_maps(struct ps_prochandle *P)
memset(prf, 0, sizeof(struct prmap_file));
prf->prf_mapname = fn;
- prf->prf_next = P->map_files[h];
- P->map_files[h] = prf;
- }
- else {
+ prf->prf_next = P->map_files[fn_h];
+ P->map_files[fn_h] = prf;
+ prf->prf_inum_next = P->map_inum[inum_h];
+ P->map_inum[inum_h] = prf;
+ } else {
free(fn);
fn = NULL;
}
@@ -644,8 +709,6 @@ Pupdate_maps(struct ps_prochandle *P)
(strcmp(prf->prf_mapname, exefile) == 0))
P->map_exec = P->num_mappings;
}
- pmptr->pr_dev = makedev(major, minor);
- pmptr->pr_inum = inode;
pmptr->pr_file = prf;
/*
@@ -855,6 +918,12 @@ Pname_to_map(struct ps_prochandle *P, const char *name)
return Plmid_to_map(P, PR_LMID_EVERY, name);
}
+const prmap_file_t *
+Pinode_to_map(struct ps_prochandle *P, dev_t dev, ino_t inum)
+{
+ return Pprmap_file_by_dev_inum(P, dev, inum);
+}
+
/*
* We wouldn't need these if qsort(3C) took an argument for the callback...
*/
diff --git a/libproc/libproc.h b/libproc/libproc.h
index 1f8683e25b31..aa6a338a0ae8 100644
--- a/libproc/libproc.h
+++ b/libproc/libproc.h
@@ -32,6 +32,7 @@
#include <sys/socket.h>
#include <sys/utsname.h>
#include <sys/time.h>
+#include <sys/types.h>
#include <sys/user.h>
#include <sys/compiler.h>
@@ -242,6 +243,8 @@ extern const prmap_t *Paddr_to_map(struct ps_prochandle *, uintptr_t);
extern const prmap_t *Pname_to_map(struct ps_prochandle *, const char *);
extern const prmap_t *Plmid_to_map(struct ps_prochandle *,
Lmid_t, const char *);
+extern const prmap_file_t *Pinode_to_map(struct ps_prochandle *,
+ dev_t, ino_t);
extern char *Pobjname(struct ps_prochandle *, uintptr_t, char *, size_t);
extern int Plmid(struct ps_prochandle *, uintptr_t, Lmid_t *);
--
2.37.1.265.g363c192786.dirty
More information about the DTrace-devel
mailing list