Implement caching of print_sockaddr_by_inode
As -yy parser, compared to -y, needs to do at least 5 extra syscalls (getxattr, socket, sendmsg, recvmsg, close) to print socket details, caching results of netlink conversations between strace and kernel noticeably reduces amount of system time spent by strace. The caching is safe since sockets do not change their addresses after successful bind or connect syscall. * defs.h (string_quote, print_sockaddr_by_inode_cached): New prototypes. * socketutils.c (cache_entry): New type. (CACHE_SIZE, CACHE_MASK): New macros. (cache): New static array. (cache_and_print_inode_details): New static function. (print_sockaddr_by_inode_cached): New function. (inet_parse_response, unix_parse_response): Use cache_and_print_inode_details. * util.c (printfd): Use string_quote and print_sockaddr_by_inode_cached. (string_quote): Remove static qualifier. * NEWS: Mention this improvement. * tests/unix-yy.c (main): Update.
This commit is contained in:
parent
69bfc89770
commit
3c17d1b5e1
2
NEWS
2
NEWS
@ -8,6 +8,8 @@ Noteworthy changes in release ?.?? (????-??-??)
|
||||
and sched_setaffinity syscalls.
|
||||
* Enhanced decoding of getxpid, getxuid, and getxgid syscalls on alpha.
|
||||
* Added decoding of bind, listen, and setsockopt direct syscalls on sparc.
|
||||
* Implemented caching of netlink conversations to reduce amount of time
|
||||
spent in decoding socket details in -yy mode.
|
||||
|
||||
* Bug fixes
|
||||
* Fixed build on arc, metag, nios2, or1k, and tile architectures.
|
||||
|
2
defs.h
2
defs.h
@ -536,6 +536,7 @@ extern int next_set_bit(const void *bit_array, unsigned cur_bit, unsigned size_b
|
||||
#define QUOTE_0_TERMINATED 0x01
|
||||
#define QUOTE_OMIT_LEADING_TRAILING_QUOTES 0x02
|
||||
|
||||
extern int string_quote(const char *, char *, unsigned int, unsigned int);
|
||||
extern int print_quoted_string(const char *, unsigned int, unsigned int);
|
||||
|
||||
/* a refers to the lower numbered u_arg,
|
||||
@ -613,6 +614,7 @@ extern void printpathn(struct tcb *, long, unsigned int);
|
||||
(sizeof(intmax_t)*3 * 2 + sizeof("{tv_sec=%jd, tv_nsec=%jd}"))
|
||||
extern void printfd(struct tcb *, int);
|
||||
extern bool print_sockaddr_by_inode(const unsigned long, const char *);
|
||||
extern bool print_sockaddr_by_inode_cached(const unsigned long);
|
||||
extern void print_dirfd(struct tcb *, int);
|
||||
extern void printsock(struct tcb *, long, int);
|
||||
extern void print_sock_optmgmt(struct tcb *, long, int);
|
||||
|
@ -45,6 +45,38 @@
|
||||
# define UNIX_PATH_MAX sizeof(((struct sockaddr_un *) 0)->sun_path)
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
unsigned long inode;
|
||||
char *details;
|
||||
} cache_entry;
|
||||
|
||||
#define CACHE_SIZE 1024U
|
||||
static cache_entry cache[CACHE_SIZE];
|
||||
#define CACHE_MASK (CACHE_SIZE - 1)
|
||||
|
||||
static int
|
||||
cache_and_print_inode_details(const unsigned long inode, char *details)
|
||||
{
|
||||
cache_entry *e = &cache[inode & CACHE_MASK];
|
||||
free(e->details);
|
||||
e->inode = inode;
|
||||
e->details = details;
|
||||
|
||||
tprints(details);
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool
|
||||
print_sockaddr_by_inode_cached(const unsigned long inode)
|
||||
{
|
||||
const cache_entry *e = &cache[inode & CACHE_MASK];
|
||||
if (e && inode == e->inode) {
|
||||
tprints(e->details);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
inet_send_query(const int fd, const int family, const int proto)
|
||||
{
|
||||
@ -114,6 +146,7 @@ inet_parse_response(const char *proto_name, const void *data,
|
||||
}
|
||||
|
||||
char src_buf[text_size];
|
||||
char *details;
|
||||
|
||||
if (!inet_ntop(diag_msg->idiag_family, diag_msg->id.idiag_src,
|
||||
src_buf, text_size))
|
||||
@ -127,16 +160,17 @@ inet_parse_response(const char *proto_name, const void *data,
|
||||
dst_buf, text_size))
|
||||
return -1;
|
||||
|
||||
tprintf("%s:[%s:%u->%s:%u]",
|
||||
proto_name,
|
||||
src_buf, ntohs(diag_msg->id.idiag_sport),
|
||||
dst_buf, ntohs(diag_msg->id.idiag_dport));
|
||||
if (asprintf(&details, "%s:[%s:%u->%s:%u]", proto_name,
|
||||
src_buf, ntohs(diag_msg->id.idiag_sport),
|
||||
dst_buf, ntohs(diag_msg->id.idiag_dport)) < 0)
|
||||
return false;
|
||||
} else {
|
||||
tprintf("%s:[%s:%u]", proto_name, src_buf,
|
||||
ntohs(diag_msg->id.idiag_sport));
|
||||
if (asprintf(&details, "%s:[%s:%u]", proto_name, src_buf,
|
||||
ntohs(diag_msg->id.idiag_sport)) < 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
return 1;
|
||||
return cache_and_print_inode_details(inode, details);
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -282,26 +316,39 @@ unix_parse_response(const char *proto_name, const void *data,
|
||||
* print obtained information in the following format:
|
||||
* "UNIX:[" SELF_INODE [ "->" PEER_INODE ][ "," SOCKET_FILE ] "]"
|
||||
*/
|
||||
if (peer || path_len) {
|
||||
tprintf("%s:[%lu", proto_name, inode);
|
||||
if (peer)
|
||||
tprintf("->%u", peer);
|
||||
if (path_len) {
|
||||
if (path[0] == '\0') {
|
||||
tprints(",@");
|
||||
print_quoted_string(path + 1, path_len,
|
||||
QUOTE_0_TERMINATED);
|
||||
} else {
|
||||
tprints(",");
|
||||
print_quoted_string(path, path_len + 1,
|
||||
QUOTE_0_TERMINATED);
|
||||
}
|
||||
}
|
||||
tprints("]");
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
if (!peer && !path_len)
|
||||
return -1;
|
||||
|
||||
char peer_str[3 + sizeof(peer) * 3];
|
||||
if (peer)
|
||||
snprintf(peer_str, sizeof(peer_str), "->%u", peer);
|
||||
else
|
||||
peer_str[0] = '\0';
|
||||
|
||||
const char *path_str;
|
||||
if (path_len) {
|
||||
char *outstr = alloca(4 * path_len + 4);
|
||||
|
||||
outstr[0] = ',';
|
||||
if (path[0] == '\0') {
|
||||
outstr[1] = '@';
|
||||
string_quote(path + 1, outstr + 2,
|
||||
path_len - 1, QUOTE_0_TERMINATED);
|
||||
} else {
|
||||
string_quote(path, outstr + 1,
|
||||
path_len, QUOTE_0_TERMINATED);
|
||||
}
|
||||
path_str = outstr;
|
||||
} else {
|
||||
path_str = "";
|
||||
}
|
||||
|
||||
char *details;
|
||||
if (asprintf(&details, "%s:[%lu%s%s]", proto_name, inode,
|
||||
peer_str, path_str) < 0)
|
||||
return -1;
|
||||
|
||||
return cache_and_print_inode_details(inode, details);
|
||||
}
|
||||
|
||||
static bool
|
||||
|
@ -141,8 +141,8 @@ main(int ac, const char **av)
|
||||
connect_fd, connect_inode, accept_inode);
|
||||
|
||||
assert(close(accept_fd) == 0);
|
||||
printf("close(%d<UNIX:[%lu,\"%s\"]>) = 0\n",
|
||||
accept_fd, accept_inode, av[1]);
|
||||
printf("close(%d<UNIX:[%lu->%lu,\"%s\"]>) = 0\n",
|
||||
accept_fd, accept_inode, connect_inode, av[1]);
|
||||
|
||||
connect_fd = socket(PF_LOCAL, SOCK_STREAM, 0);
|
||||
if (connect_fd < 0)
|
||||
@ -213,8 +213,8 @@ main(int ac, const char **av)
|
||||
connect_fd, connect_inode, accept_inode, sun_path1);
|
||||
|
||||
assert(close(accept_fd) == 0);
|
||||
printf("close(%d<UNIX:[%lu,\"%s\"]>) = 0\n",
|
||||
accept_fd, accept_inode, av[1]);
|
||||
printf("close(%d<UNIX:[%lu->%lu,\"%s\"]>) = 0\n",
|
||||
accept_fd, accept_inode, connect_inode, av[1]);
|
||||
|
||||
assert(unlink(av[1]) == 0);
|
||||
|
||||
|
18
util.c
18
util.c
@ -512,14 +512,16 @@ printfd(struct tcb *tcp, int fd)
|
||||
if (show_fd_path > 1 &&
|
||||
strncmp(path, socket_prefix, socket_prefix_len) == 0 &&
|
||||
path[path_len - 1] == ']') {
|
||||
unsigned long inodenr =
|
||||
unsigned long inode =
|
||||
strtoul(path + socket_prefix_len, NULL, 10);
|
||||
#define PROTO_NAME_LEN 32
|
||||
char proto_buf[PROTO_NAME_LEN];
|
||||
const char *proto =
|
||||
getfdproto(tcp, fd, proto_buf, PROTO_NAME_LEN);
|
||||
if (!print_sockaddr_by_inode(inodenr, proto))
|
||||
tprints(path);
|
||||
|
||||
if (!print_sockaddr_by_inode_cached(inode)) {
|
||||
char buf[256];
|
||||
const char *proto =
|
||||
getfdproto(tcp, fd, buf, sizeof(buf));
|
||||
if (!print_sockaddr_by_inode(inode, proto))
|
||||
tprints(path);
|
||||
}
|
||||
} else {
|
||||
print_quoted_string(path, path_len,
|
||||
QUOTE_OMIT_LEADING_TRAILING_QUOTES);
|
||||
@ -543,7 +545,7 @@ printfd(struct tcb *tcp, int fd)
|
||||
* Returns 0 if QUOTE_0_TERMINATED is set and NUL was seen, 1 otherwise.
|
||||
* Note that if QUOTE_0_TERMINATED is not set, always returns 1.
|
||||
*/
|
||||
static int
|
||||
int
|
||||
string_quote(const char *instr, char *outstr, const unsigned int size,
|
||||
const unsigned int style)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user