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). */ |
/* The msgid_ihash table maps msgh_id values to names. */ |
52 |
|
|
53 |
|
struct msgid_info |
54 |
|
{ |
55 |
|
char *name; |
56 |
|
char *subsystem; |
57 |
|
}; |
58 |
|
|
59 |
static void |
static void |
60 |
msgid_ihash_cleanup (void *element, void *arg) |
msgid_ihash_cleanup (void *element, void *arg) |
61 |
{ |
{ |
62 |
free (element); |
struct msgid_info *info = element; |
63 |
|
free (info->name); |
64 |
|
free (info->subsystem); |
65 |
|
free (info); |
66 |
} |
} |
67 |
|
|
68 |
static struct ihash msgid_ihash = { cleanup: msgid_ihash_cleanup }; |
static struct ihash msgid_ihash = { cleanup: msgid_ihash_cleanup }; |
77 |
char *buffer = NULL; |
char *buffer = NULL; |
78 |
size_t bufsize = 0; |
size_t bufsize = 0; |
79 |
unsigned int lineno = 0; |
unsigned int lineno = 0; |
80 |
char *name; |
char *name, *subsystem; |
81 |
unsigned int msgid; |
unsigned int msgid; |
82 |
|
|
83 |
fp = fopen (filename, "r"); |
fp = fopen (filename, "r"); |
92 |
++lineno; |
++lineno; |
93 |
if (buffer[0] == '#' || buffer[0] == '\0') |
if (buffer[0] == '#' || buffer[0] == '\0') |
94 |
continue; |
continue; |
95 |
if (sscanf (buffer, "%*s %*u %as %*u %u %*u\n", &name, &msgid) != 2) |
if (sscanf (buffer, "%as %*u %as %*u %u %*u\n", |
96 |
|
&subsystem, &name, &msgid) != 2) |
97 |
error (0, 0, "%s:%u: invalid format in RPC list file", |
error (0, 0, "%s:%u: invalid format in RPC list file", |
98 |
filename, lineno); |
filename, lineno); |
99 |
else |
else |
100 |
{ |
{ |
101 |
error_t err = ihash_add (&msgid_ihash, msgid, name, NULL); |
struct msgid_info *info = malloc (sizeof *info); |
102 |
if (err) |
if (info == 0) |
103 |
error (1, err, "ihash_add"); |
error (1, errno, "malloc"); |
104 |
|
info->name = name; |
105 |
|
info->subsystem = subsystem; |
106 |
|
errno = ihash_add (&msgid_ihash, msgid, info, NULL); |
107 |
|
if (errno) |
108 |
|
error (1, errno, "ihash_add"); |
109 |
} |
} |
110 |
} |
} |
111 |
|
|
116 |
/* Look for a name describing MSGID. We check the table directly, and |
/* Look for a name describing MSGID. We check the table directly, and |
117 |
also check if this looks like the ID of a reply message whose request |
also check if this looks like the ID of a reply message whose request |
118 |
ID is already in the table. */ |
ID is already in the table. */ |
119 |
static const char * |
static const struct msgid_info * |
120 |
msgid_name (mach_msg_id_t msgid) |
msgid_info (mach_msg_id_t msgid) |
121 |
{ |
{ |
122 |
const char *msgname = ihash_find (&msgid_ihash, msgid); |
const struct msgid_info *info = ihash_find (&msgid_ihash, msgid); |
123 |
if (msgname == 0 && (msgid / 100) % 2 == 1) |
if (info == 0 && (msgid / 100) % 2 == 1) |
124 |
{ |
{ |
125 |
/* This message ID is not in the table, and its number makes it |
/* This message ID is not in the table, and its number makes it |
126 |
what should be an RPC reply message ID. So look up the message |
what should be an RPC reply message ID. So look up the message |
127 |
ID of the corresponding RPC request and synthesize a name from |
ID of the corresponding RPC request and synthesize a name from |
128 |
that. Then stash that name in the table so the next time the |
that. Then stash that name in the table so the next time the |
129 |
lookup will match directly. */ |
lookup will match directly. */ |
130 |
msgname = ihash_find (&msgid_ihash, msgid - 100); |
info = ihash_find (&msgid_ihash, msgid - 100); |
131 |
if (msgname != 0) |
if (info != 0) |
132 |
{ |
{ |
133 |
char *reply_name = 0; |
struct msgid_info *reply_info = malloc (sizeof *info); |
134 |
asprintf (&reply_name, "%s-reply", reply_name); |
if (reply_info != 0) |
|
if (reply_name != 0) |
|
135 |
{ |
{ |
136 |
ihash_add (&msgid_ihash, msgid, reply_name, NULL); |
reply_info->subsystem = strdup (info->subsystem); |
137 |
msgname = reply_name; |
reply_info->name = 0; |
138 |
|
asprintf (&reply_info->name, "%s-reply", info->name); |
139 |
|
ihash_add (&msgid_ihash, msgid, reply_info, NULL); |
140 |
|
info = reply_info; |
141 |
} |
} |
142 |
else |
else |
143 |
msgname = 0; |
info = 0; |
144 |
} |
} |
145 |
} |
} |
146 |
return msgname; |
return info; |
147 |
|
} |
148 |
|
|
149 |
|
static const char * |
150 |
|
msgid_name (mach_msg_id_t msgid) |
151 |
|
{ |
152 |
|
const struct msgid_info *info = msgid_info (msgid); |
153 |
|
return info ? info->name : 0; |
154 |
|
} |
155 |
|
|
156 |
|
/* Return true if this message's data should be printed out. |
157 |
|
For a request message, that means the in parameters. |
158 |
|
For a reply messages, that means the return code and out parameters. */ |
159 |
|
static int |
160 |
|
msgid_display (const struct msgid_info *info) |
161 |
|
{ |
162 |
|
return 1; |
163 |
|
} |
164 |
|
|
165 |
|
/* Return true if we should interpose on this RPC's reply port. If this |
166 |
|
returns false, we will pass the caller's original reply port through so |
167 |
|
we never see the reply message at all. */ |
168 |
|
static int |
169 |
|
msgid_trace_replies (const struct msgid_info *info) |
170 |
|
{ |
171 |
|
return 1; |
172 |
} |
} |
173 |
|
|
174 |
/* 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. */ |
636 |
}; |
}; |
637 |
|
|
638 |
error_t err; |
error_t err; |
639 |
|
const struct msgid_info *msgid; |
640 |
struct traced_info *info; |
struct traced_info *info; |
641 |
mach_msg_bits_t complex; |
mach_msg_bits_t complex; |
642 |
|
|
683 |
|
|
684 |
complex = inp->msgh_bits & MACH_MSGH_BITS_COMPLEX; |
complex = inp->msgh_bits & MACH_MSGH_BITS_COMPLEX; |
685 |
|
|
686 |
|
msgid = msgid_info (inp->msgh_id); |
687 |
|
|
688 |
/* Swap the header data like a crossover cable. */ |
/* Swap the header data like a crossover cable. */ |
689 |
{ |
{ |
690 |
mach_msg_type_name_t this_type = MACH_MSGH_BITS_LOCAL (inp->msgh_bits); |
mach_msg_type_name_t this_type = MACH_MSGH_BITS_LOCAL (inp->msgh_bits); |
691 |
mach_msg_type_name_t reply_type = MACH_MSGH_BITS_REMOTE (inp->msgh_bits); |
mach_msg_type_name_t reply_type = MACH_MSGH_BITS_REMOTE (inp->msgh_bits); |
692 |
|
|
693 |
inp->msgh_local_port = inp->msgh_remote_port; |
inp->msgh_local_port = inp->msgh_remote_port; |
694 |
if (reply_type) |
if (reply_type && msgid_trace_replies (msgid)) |
695 |
{ |
{ |
696 |
struct traced_info *info; |
struct traced_info *info; |
697 |
info = rewrite_right (&inp->msgh_local_port, &reply_type); |
info = rewrite_right (&inp->msgh_local_port, &reply_type); |
698 |
assert (info); |
assert (info); |
699 |
if (info->name == 0) |
if (info->name == 0) |
700 |
{ |
{ |
701 |
const char *msgname = msgid_name (inp->msgh_id); |
if (msgid == 0) |
|
if (msgname == 0) |
|
702 |
asprintf (&info->name, "reply(%u:%u)", |
asprintf (&info->name, "reply(%u:%u)", |
703 |
(unsigned int) info->pi.port_right, |
(unsigned int) info->pi.port_right, |
704 |
(unsigned int) inp->msgh_id); |
(unsigned int) inp->msgh_id); |
705 |
else |
else |
706 |
asprintf (&info->name, "reply(%u:%s)", |
asprintf (&info->name, "reply(%u:%s)", |
707 |
(unsigned int) info->pi.port_right, msgname); |
(unsigned int) info->pi.port_right, msgid->name); |
708 |
} |
} |
709 |
if (info->type == MACH_MSG_TYPE_MOVE_SEND_ONCE) |
if (info->type == MACH_MSG_TYPE_MOVE_SEND_ONCE) |
710 |
{ |
{ |
735 |
/* The message now appears as it would if we were the sender. |
/* The message now appears as it would if we were the sender. |
736 |
It is ready to be resent. */ |
It is ready to be resent. */ |
737 |
|
|
738 |
if (inp->msgh_local_port == MACH_PORT_NULL |
if (msgid_display (msgid)) |
|
&& info->type == MACH_MSG_TYPE_MOVE_SEND_ONCE |
|
|
&& inp->msgh_size >= sizeof (mig_reply_header_t) |
|
|
&& (*(int *) &((mig_reply_header_t *) inp)->RetCodeType |
|
|
== *(int *)&RetCodeType)) |
|
|
{ |
|
|
/* This sure looks like an RPC reply message. */ |
|
|
mig_reply_header_t *rh = (void *) inp; |
|
|
print_reply_header (info, rh); |
|
|
putc (' ', ostream); |
|
|
print_contents (&rh->Head, rh + 1); |
|
|
putc ('\n', ostream); |
|
|
} |
|
|
else |
|
739 |
{ |
{ |
740 |
/* Print something about the message header. */ |
if (inp->msgh_local_port == MACH_PORT_NULL |
741 |
print_request_header (info, inp); |
&& info->type == MACH_MSG_TYPE_MOVE_SEND_ONCE |
742 |
print_contents (inp, inp + 1); |
&& inp->msgh_size >= sizeof (mig_reply_header_t) |
743 |
if (inp->msgh_local_port == MACH_PORT_NULL) /* simpleroutine */ |
&& (*(int *) &((mig_reply_header_t *) inp)->RetCodeType |
744 |
fprintf (ostream, ");\n"); |
== *(int *)&RetCodeType)) |
745 |
|
{ |
746 |
|
/* This sure looks like an RPC reply message. */ |
747 |
|
mig_reply_header_t *rh = (void *) inp; |
748 |
|
print_reply_header (info, rh); |
749 |
|
putc (' ', ostream); |
750 |
|
print_contents (&rh->Head, rh + 1); |
751 |
|
putc ('\n', ostream); |
752 |
|
} |
753 |
else |
else |
754 |
/* Leave a partial line that will be finished later. */ |
{ |
755 |
fprintf (ostream, ")"); |
/* Print something about the message header. */ |
756 |
|
print_request_header (info, inp); |
757 |
|
print_contents (inp, inp + 1); |
758 |
|
if (inp->msgh_local_port == MACH_PORT_NULL) /* simpleroutine */ |
759 |
|
fprintf (ostream, ");\n"); |
760 |
|
else |
761 |
|
/* Leave a partial line that will be finished later. */ |
762 |
|
fprintf (ostream, ")"); |
763 |
|
} |
764 |
} |
} |
765 |
|
|
766 |
/* Resend the message to the tracee. */ |
/* Resend the message to the tracee. */ |