35 |
|
|
36 |
const char *argp_program_version = STANDARD_HURD_VERSION (rpctrace); |
const char *argp_program_version = STANDARD_HURD_VERSION (rpctrace); |
37 |
|
|
38 |
static const struct argp_option options[] = { |
static const struct argp_option options[] = |
39 |
|
{ |
40 |
{"output", 'o', "FILE", 0, "Send trace output to FILE instead of stderr."}, |
{"output", 'o', "FILE", 0, "Send trace output to FILE instead of stderr."}, |
41 |
|
{"rpc-list", 'I', "FILE", 0, |
42 |
|
"Read FILE for assocations of message ID numbers to names."}, |
43 |
{0} |
{0} |
44 |
}; |
}; |
45 |
|
|
48 |
"Trace Mach Remote Procedure Calls." |
"Trace Mach Remote Procedure Calls." |
49 |
"\v."; |
"\v."; |
50 |
|
|
51 |
|
/* The msgid_ihash table maps msgh_id values to names (malloc'd strings). */ |
52 |
|
|
53 |
|
static void |
54 |
|
msgid_ihash_cleanup (void *element, void *arg) |
55 |
|
{ |
56 |
|
free (element); |
57 |
|
} |
58 |
|
|
59 |
|
static struct ihash msgid_ihash = { cleanup: msgid_ihash_cleanup }; |
60 |
|
|
61 |
|
/* Parse a file of RPC names and message IDs as output by mig's -list |
62 |
|
option: "subsystem base-id routine n request-id reply-id". Put each |
63 |
|
request-id value into `msgid_ihash' with the routine name as its value. */ |
64 |
|
static void |
65 |
|
parse_msgid_list (const char *filename) |
66 |
|
{ |
67 |
|
FILE *fp; |
68 |
|
char *buffer = NULL; |
69 |
|
size_t bufsize = 0; |
70 |
|
unsigned int lineno = 0; |
71 |
|
char *name; |
72 |
|
unsigned int msgid; |
73 |
|
|
74 |
|
fp = fopen (filename, "r"); |
75 |
|
if (fp == 0) |
76 |
|
{ |
77 |
|
error (2, errno, "%s", filename); |
78 |
|
return; |
79 |
|
} |
80 |
|
|
81 |
|
while (getline (&buffer, &bufsize, fp) > 0) |
82 |
|
{ |
83 |
|
++lineno; |
84 |
|
if (buffer[0] == '#' || buffer[0] == '\0') |
85 |
|
continue; |
86 |
|
if (sscanf (buffer, "%*s %*u %as %*u %u %*u\n", &name, &msgid) != 2) |
87 |
|
error (0, 0, "%s:%u: invalid format in RPC list file", |
88 |
|
filename, lineno); |
89 |
|
else |
90 |
|
{ |
91 |
|
error_t err = ihash_add (&msgid_ihash, msgid, name, NULL); |
92 |
|
if (err) |
93 |
|
error (1, err, "ihash_add"); |
94 |
|
} |
95 |
|
} |
96 |
|
|
97 |
|
free (buffer); |
98 |
|
fclose (fp); |
99 |
|
} |
100 |
|
|
101 |
|
/* Look for a name describing MSGID. We check the table directly, and |
102 |
|
also check if this looks like the ID of a reply message whose request |
103 |
|
ID is already in the table. */ |
104 |
|
static const char * |
105 |
|
msgid_name (mach_msg_id_t msgid) |
106 |
|
{ |
107 |
|
const char *msgname = ihash_find (&msgid_ihash, msgid); |
108 |
|
if (msgname == 0 && (msgid / 100) % 2 == 1) |
109 |
|
{ |
110 |
|
/* This message ID is not in the table, and its number makes it |
111 |
|
what should be an RPC reply message ID. So look up the message |
112 |
|
ID of the corresponding RPC request and synthesize a name from |
113 |
|
that. Then stash that name in the table so the next time the |
114 |
|
lookup will match directly. */ |
115 |
|
msgname = ihash_find (&msgid_ihash, msgid - 100); |
116 |
|
if (msgname != 0) |
117 |
|
{ |
118 |
|
char *reply_name = 0; |
119 |
|
asprintf (&reply_name, "%s-reply", reply_name); |
120 |
|
if (reply_name != 0) |
121 |
|
{ |
122 |
|
ihash_add (&msgid_ihash, msgid, reply_name, NULL); |
123 |
|
msgname = reply_name; |
124 |
|
} |
125 |
|
else |
126 |
|
msgname = 0; |
127 |
|
} |
128 |
|
} |
129 |
|
return msgname; |
130 |
|
} |
131 |
|
|
132 |
/* We keep one of these structures for each port right we are tracing. */ |
/* We keep one of these structures for each port right we are tracing. */ |
133 |
struct traced_info |
struct traced_info |
134 |
{ |
{ |
652 |
info = rewrite_right (&inp->msgh_local_port, &reply_type); |
info = rewrite_right (&inp->msgh_local_port, &reply_type); |
653 |
assert (info); |
assert (info); |
654 |
if (info->name == 0) |
if (info->name == 0) |
655 |
asprintf (&info->name, "reply(%u:%u)", |
{ |
656 |
(unsigned int) info->pi.port_right, |
const char *msgname = msgid_name (inp->msgh_id); |
657 |
(unsigned int) inp->msgh_id); |
if (msgname == 0) |
658 |
|
asprintf (&info->name, "reply(%u:%u)", |
659 |
|
(unsigned int) info->pi.port_right, |
660 |
|
(unsigned int) inp->msgh_id); |
661 |
|
else |
662 |
|
asprintf (&info->name, "reply(%u:%s)", |
663 |
|
(unsigned int) info->pi.port_right, msgname); |
664 |
|
} |
665 |
if (info->type == MACH_MSG_TYPE_MOVE_SEND_ONCE) |
if (info->type == MACH_MSG_TYPE_MOVE_SEND_ONCE) |
666 |
{ |
{ |
667 |
info->u.send_once.sent_to = info->pi.port_right; |
info->u.send_once.sent_to = info->pi.port_right; |
780 |
static void |
static void |
781 |
print_request_header (struct traced_info *receiver, mach_msg_header_t *msg) |
print_request_header (struct traced_info *receiver, mach_msg_header_t *msg) |
782 |
{ |
{ |
783 |
|
const char *msgname = msgid_name (msg->msgh_id); |
784 |
|
|
785 |
expected_reply_port = msg->msgh_local_port; |
expected_reply_port = msg->msgh_local_port; |
786 |
|
|
787 |
if (receiver->name != 0) |
if (receiver->name != 0) |
788 |
fprintf (ostream, "%4s->%5u (", receiver->name, msg->msgh_id); |
fprintf (ostream, "%4s->", receiver->name); |
789 |
|
else |
790 |
|
fprintf (ostream, "%4u->", (unsigned int) receiver->pi.port_right); |
791 |
|
|
792 |
|
if (msgname != 0) |
793 |
|
fprintf (ostream, "%5s (", msgname); |
794 |
else |
else |
795 |
fprintf (ostream, "%4u->%5u (", |
fprintf (ostream, "%5u (", (unsigned int) msg->msgh_id); |
|
(unsigned int) receiver->pi.port_right, msg->msgh_id); |
|
796 |
} |
} |
797 |
|
|
798 |
static void |
static void |
838 |
/* This is a normal reply to a previous request. */ |
/* This is a normal reply to a previous request. */ |
839 |
fprintf (ostream, " > "); |
fprintf (ostream, " > "); |
840 |
else |
else |
841 |
/* Weirdo. */ |
{ |
842 |
fprintf (ostream, " >(%u) ", reply->Head.msgh_id); |
/* Weirdo. */ |
843 |
|
const char *msgname = msgid_name (reply->Head.msgh_id); |
844 |
|
if (msgname == 0) |
845 |
|
fprintf (ostream, " >(%u) ", reply->Head.msgh_id); |
846 |
|
else |
847 |
|
fprintf (ostream, " >(%s) ", msgname); |
848 |
|
} |
849 |
} |
} |
850 |
|
|
851 |
if (reply->RetCode == 0) |
if (reply->RetCode == 0) |
1020 |
outfile = arg; |
outfile = arg; |
1021 |
break; |
break; |
1022 |
|
|
1023 |
|
case 'I': |
1024 |
|
parse_msgid_list (arg); |
1025 |
|
break; |
1026 |
|
|
1027 |
case ARGP_KEY_NO_ARGS: |
case ARGP_KEY_NO_ARGS: |
1028 |
argp_usage (state); |
argp_usage (state); |
1029 |
return EINVAL; |
return EINVAL; |