1*b725ae77Skettenis /* Kernel Object Display facility for Cisco
2*b725ae77Skettenis Copyright 1999, 2000 Free Software Foundation, Inc.
3*b725ae77Skettenis
4*b725ae77Skettenis Written by Tom Tromey <tromey@cygnus.com>.
5*b725ae77Skettenis
6*b725ae77Skettenis This file is part of GDB.
7*b725ae77Skettenis
8*b725ae77Skettenis This program is free software; you can redistribute it and/or modify
9*b725ae77Skettenis it under the terms of the GNU General Public License as published by
10*b725ae77Skettenis the Free Software Foundation; either version 2 of the License, or
11*b725ae77Skettenis (at your option) any later version.
12*b725ae77Skettenis
13*b725ae77Skettenis This program is distributed in the hope that it will be useful,
14*b725ae77Skettenis but WITHOUT ANY WARRANTY; without even the implied warranty of
15*b725ae77Skettenis MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16*b725ae77Skettenis GNU General Public License for more details.
17*b725ae77Skettenis
18*b725ae77Skettenis You should have received a copy of the GNU General Public License
19*b725ae77Skettenis along with this program; if not, write to the Free Software
20*b725ae77Skettenis Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
21*b725ae77Skettenis
22*b725ae77Skettenis #include "defs.h"
23*b725ae77Skettenis #include "gdb_string.h"
24*b725ae77Skettenis #include "kod.h"
25*b725ae77Skettenis
26*b725ae77Skettenis #ifdef HAVE_STDLIB_H
27*b725ae77Skettenis #include <stdlib.h>
28*b725ae77Skettenis #endif
29*b725ae77Skettenis
30*b725ae77Skettenis /* Define this to turn off communication with target. */
31*b725ae77Skettenis /* #define FAKE_PACKET */
32*b725ae77Skettenis
33*b725ae77Skettenis /* Size of buffer used for remote communication. */
34*b725ae77Skettenis #define PBUFSIZ 400
35*b725ae77Skettenis
36*b725ae77Skettenis /* Pointers to gdb callbacks. */
37*b725ae77Skettenis static void (*gdb_kod_display) (char *);
38*b725ae77Skettenis static void (*gdb_kod_query) (char *, char *, int *);
39*b725ae77Skettenis
40*b725ae77Skettenis
41*b725ae77Skettenis
42*b725ae77Skettenis /* Initialize and return library name and version.
43*b725ae77Skettenis The gdb side of KOD, kod.c, passes us two functions: one for
44*b725ae77Skettenis displaying output (presumably to the user) and the other for
45*b725ae77Skettenis querying the target. */
46*b725ae77Skettenis char *
cisco_kod_open(kod_display_callback_ftype * display_func,kod_query_callback_ftype * query_func)47*b725ae77Skettenis cisco_kod_open (kod_display_callback_ftype *display_func,
48*b725ae77Skettenis kod_query_callback_ftype *query_func)
49*b725ae77Skettenis {
50*b725ae77Skettenis char buffer[PBUFSIZ];
51*b725ae77Skettenis int bufsiz = PBUFSIZ;
52*b725ae77Skettenis int i, count;
53*b725ae77Skettenis
54*b725ae77Skettenis gdb_kod_display = display_func;
55*b725ae77Skettenis gdb_kod_query = query_func;
56*b725ae77Skettenis
57*b725ae77Skettenis /* Get the OS info, and check the version field. This is the stub
58*b725ae77Skettenis version, which we use to see whether we will understand what
59*b725ae77Skettenis comes back. This is lame, but the `qKoL' request doesn't
60*b725ae77Skettenis actually provide enough configurability.
61*b725ae77Skettenis
62*b725ae77Skettenis Right now the only defined version number is `0.0.0'.
63*b725ae77Skettenis This stub supports qKoI and the `a' (any) object requests qKaL
64*b725ae77Skettenis and qKaI. Each `a' object is returned as a 4-byte integer ID.
65*b725ae77Skettenis An info request on an object returns a pair of 4-byte integers;
66*b725ae77Skettenis the first is the object pointer and the second is the thread ID. */
67*b725ae77Skettenis
68*b725ae77Skettenis #ifndef FAKE_PACKET
69*b725ae77Skettenis (*gdb_kod_query) ("oI;", buffer, &bufsiz);
70*b725ae77Skettenis #else
71*b725ae77Skettenis strcpy (buffer, "Cisco IOS/Classic/13.4 0.0.0");
72*b725ae77Skettenis #endif
73*b725ae77Skettenis
74*b725ae77Skettenis count = 2;
75*b725ae77Skettenis for (i = 0; count && buffer[i] != '\0'; ++i)
76*b725ae77Skettenis {
77*b725ae77Skettenis if (buffer[i] == ' ')
78*b725ae77Skettenis --count;
79*b725ae77Skettenis }
80*b725ae77Skettenis
81*b725ae77Skettenis if (buffer[i] == '\0')
82*b725ae77Skettenis error ("Remote returned malformed packet\n");
83*b725ae77Skettenis if (strcmp (&buffer[i], "0.0.0"))
84*b725ae77Skettenis error ("Remote returned unknown stub version: %s\n", &buffer[i]);
85*b725ae77Skettenis
86*b725ae77Skettenis /* Return name, version, and description. I hope we have enough
87*b725ae77Skettenis space. */
88*b725ae77Skettenis return (xstrdup ("gdbkodcisco v0.0.0 - Cisco Kernel Object Display"));
89*b725ae77Skettenis }
90*b725ae77Skettenis
91*b725ae77Skettenis /* Close the connection. */
92*b725ae77Skettenis void
cisco_kod_close(void)93*b725ae77Skettenis cisco_kod_close (void)
94*b725ae77Skettenis {
95*b725ae77Skettenis }
96*b725ae77Skettenis
97*b725ae77Skettenis /* Print a "bad packet" message. */
98*b725ae77Skettenis static void
bad_packet(void)99*b725ae77Skettenis bad_packet (void)
100*b725ae77Skettenis {
101*b725ae77Skettenis (*gdb_kod_display) ("Remote target returned malformed packet.\n");
102*b725ae77Skettenis }
103*b725ae77Skettenis
104*b725ae77Skettenis /* Print information about currently known kernel objects.
105*b725ae77Skettenis We currently ignore the argument. There is only one mode of
106*b725ae77Skettenis querying the Cisco kernel: we ask for a dump of everything, and
107*b725ae77Skettenis it returns it. */
108*b725ae77Skettenis void
cisco_kod_request(char * arg,int from_tty)109*b725ae77Skettenis cisco_kod_request (char *arg, int from_tty)
110*b725ae77Skettenis {
111*b725ae77Skettenis char buffer[PBUFSIZ], command[PBUFSIZ];
112*b725ae77Skettenis int done = 0, i;
113*b725ae77Skettenis int fail = 0;
114*b725ae77Skettenis
115*b725ae77Skettenis char **sync_ids = NULL;
116*b725ae77Skettenis int sync_len = 0;
117*b725ae77Skettenis int sync_next = 0;
118*b725ae77Skettenis char *prev_id = NULL;
119*b725ae77Skettenis
120*b725ae77Skettenis if (! arg || strcmp (arg, "any"))
121*b725ae77Skettenis {
122*b725ae77Skettenis /* "Top-level" command. This is really silly, but it also seems
123*b725ae77Skettenis to be how KOD is defined. */
124*b725ae77Skettenis /* Even sillier is the fact that this first line must start
125*b725ae77Skettenis with the word "List". See kod.tcl. */
126*b725ae77Skettenis (*gdb_kod_display) ("List of Cisco Kernel Objects\n");
127*b725ae77Skettenis (*gdb_kod_display) ("Object\tDescription\n");
128*b725ae77Skettenis (*gdb_kod_display) ("any\tAny and all objects\n");
129*b725ae77Skettenis return;
130*b725ae77Skettenis }
131*b725ae77Skettenis
132*b725ae77Skettenis while (! done)
133*b725ae77Skettenis {
134*b725ae77Skettenis int off = 0; /* Where we are in the string. */
135*b725ae77Skettenis long count; /* Number of objects in this packet. */
136*b725ae77Skettenis int bufsiz = PBUFSIZ;
137*b725ae77Skettenis char *s_end;
138*b725ae77Skettenis
139*b725ae77Skettenis strcpy (command, "aL");
140*b725ae77Skettenis if (prev_id)
141*b725ae77Skettenis {
142*b725ae77Skettenis strcat (command, ",");
143*b725ae77Skettenis strcat (command, prev_id);
144*b725ae77Skettenis }
145*b725ae77Skettenis strcat (command, ";");
146*b725ae77Skettenis
147*b725ae77Skettenis #ifndef FAKE_PACKET
148*b725ae77Skettenis /* We talk to the target by calling through the query function
149*b725ae77Skettenis passed to us when we were initialized. */
150*b725ae77Skettenis (*gdb_kod_query) (command, buffer, &bufsiz);
151*b725ae77Skettenis #else
152*b725ae77Skettenis /* Fake up a multi-part packet. */
153*b725ae77Skettenis if (! strncmp (&command[3], "a500005a", 8))
154*b725ae77Skettenis strcpy (buffer, "KAL,01,1,f500005f;f500005f;");
155*b725ae77Skettenis else
156*b725ae77Skettenis strcpy (buffer, "KAL,02,0,a500005a;a500005a;de02869f;");
157*b725ae77Skettenis #endif
158*b725ae77Skettenis
159*b725ae77Skettenis /* Empty response is an error. */
160*b725ae77Skettenis if (strlen (buffer) == 0)
161*b725ae77Skettenis {
162*b725ae77Skettenis (*gdb_kod_display) ("Remote target did not recognize kernel object query command.\n");
163*b725ae77Skettenis fail = 1;
164*b725ae77Skettenis break;
165*b725ae77Skettenis }
166*b725ae77Skettenis
167*b725ae77Skettenis /* If we don't get a `K' response then the buffer holds the
168*b725ae77Skettenis target's error message. */
169*b725ae77Skettenis if (buffer[0] != 'K')
170*b725ae77Skettenis {
171*b725ae77Skettenis (*gdb_kod_display) (buffer);
172*b725ae77Skettenis fail = 1;
173*b725ae77Skettenis break;
174*b725ae77Skettenis }
175*b725ae77Skettenis
176*b725ae77Skettenis /* Make sure we get the response we expect. */
177*b725ae77Skettenis if (strncmp (buffer, "KAL,", 4))
178*b725ae77Skettenis {
179*b725ae77Skettenis bad_packet ();
180*b725ae77Skettenis fail = 1;
181*b725ae77Skettenis break;
182*b725ae77Skettenis }
183*b725ae77Skettenis off += 4;
184*b725ae77Skettenis
185*b725ae77Skettenis /* Parse out the count. We expect to convert exactly two
186*b725ae77Skettenis characters followed by a comma. */
187*b725ae77Skettenis count = strtol (&buffer[off], &s_end, 16);
188*b725ae77Skettenis if (s_end - &buffer[off] != 2 || buffer[off + 2] != ',')
189*b725ae77Skettenis {
190*b725ae77Skettenis bad_packet ();
191*b725ae77Skettenis fail = 1;
192*b725ae77Skettenis break;
193*b725ae77Skettenis }
194*b725ae77Skettenis off += 3;
195*b725ae77Skettenis
196*b725ae77Skettenis /* Parse out the `done' flag. */
197*b725ae77Skettenis if ((buffer[off] != '0' && buffer[off] != '1')
198*b725ae77Skettenis || buffer[off + 1] != ',')
199*b725ae77Skettenis {
200*b725ae77Skettenis bad_packet ();
201*b725ae77Skettenis fail = 1;
202*b725ae77Skettenis break;
203*b725ae77Skettenis }
204*b725ae77Skettenis done = buffer[off] == '1';
205*b725ae77Skettenis off += 2;
206*b725ae77Skettenis
207*b725ae77Skettenis /* Id of the last item; we might this to construct the next
208*b725ae77Skettenis request. */
209*b725ae77Skettenis prev_id = &buffer[off];
210*b725ae77Skettenis if (strlen (prev_id) < 8 || buffer[off + 8] != ';')
211*b725ae77Skettenis {
212*b725ae77Skettenis bad_packet ();
213*b725ae77Skettenis fail = 1;
214*b725ae77Skettenis break;
215*b725ae77Skettenis }
216*b725ae77Skettenis buffer[off + 8] = '\0';
217*b725ae77Skettenis off += 9;
218*b725ae77Skettenis
219*b725ae77Skettenis sync_len += count;
220*b725ae77Skettenis sync_ids = (char **) xrealloc (sync_ids, sync_len * sizeof (char *));
221*b725ae77Skettenis
222*b725ae77Skettenis for (i = 0; i < count; ++i)
223*b725ae77Skettenis {
224*b725ae77Skettenis if (strlen (&buffer[off]) < 8 || buffer[off + 8] != ';')
225*b725ae77Skettenis {
226*b725ae77Skettenis bad_packet ();
227*b725ae77Skettenis fail = 1;
228*b725ae77Skettenis break;
229*b725ae77Skettenis }
230*b725ae77Skettenis buffer[off + 8] = '\0';
231*b725ae77Skettenis sync_ids[sync_next++] = xstrdup (&buffer[off]);
232*b725ae77Skettenis off += 9;
233*b725ae77Skettenis }
234*b725ae77Skettenis
235*b725ae77Skettenis if (buffer[off] != '\0')
236*b725ae77Skettenis {
237*b725ae77Skettenis bad_packet ();
238*b725ae77Skettenis fail = 1;
239*b725ae77Skettenis break;
240*b725ae77Skettenis }
241*b725ae77Skettenis }
242*b725ae77Skettenis
243*b725ae77Skettenis /* We've collected all the sync object IDs. Now query to get the
244*b725ae77Skettenis specific information, and arrange to print this info. */
245*b725ae77Skettenis if (! fail)
246*b725ae77Skettenis {
247*b725ae77Skettenis (*gdb_kod_display) ("Object ID\tObject Pointer\tThread ID\n");
248*b725ae77Skettenis
249*b725ae77Skettenis for (i = 0; i < sync_next; ++i)
250*b725ae77Skettenis {
251*b725ae77Skettenis int off = 0;
252*b725ae77Skettenis int bufsiz = PBUFSIZ;
253*b725ae77Skettenis
254*b725ae77Skettenis /* For now assume a query can be accomplished in a single
255*b725ae77Skettenis transaction. This is implied in the protocol document.
256*b725ae77Skettenis See comments above, and the KOD protocol document, to
257*b725ae77Skettenis understand the parsing of the return value. */
258*b725ae77Skettenis strcpy (command, "aI,");
259*b725ae77Skettenis strcat (command, sync_ids[i]);
260*b725ae77Skettenis strcat (command, ";");
261*b725ae77Skettenis
262*b725ae77Skettenis #ifndef FAKE_PACKET
263*b725ae77Skettenis (*gdb_kod_query) (command, buffer, &bufsiz);
264*b725ae77Skettenis #else
265*b725ae77Skettenis strcpy (buffer, "KAI,");
266*b725ae77Skettenis strcat (buffer, sync_ids[i]);
267*b725ae77Skettenis strcat (buffer, ",ffef00a0,cd00123d;");
268*b725ae77Skettenis #endif
269*b725ae77Skettenis
270*b725ae77Skettenis if (strlen (buffer) == 0)
271*b725ae77Skettenis {
272*b725ae77Skettenis (*gdb_kod_display) ("Remote target did not recognize KOD command.\n");
273*b725ae77Skettenis break;
274*b725ae77Skettenis }
275*b725ae77Skettenis
276*b725ae77Skettenis if (strncmp (buffer, "KAI,", 4))
277*b725ae77Skettenis {
278*b725ae77Skettenis bad_packet ();
279*b725ae77Skettenis break;
280*b725ae77Skettenis }
281*b725ae77Skettenis off += 4;
282*b725ae77Skettenis
283*b725ae77Skettenis if (strncmp (&buffer[off], sync_ids[i], 8)
284*b725ae77Skettenis || buffer[off + 8] != ',')
285*b725ae77Skettenis {
286*b725ae77Skettenis bad_packet ();
287*b725ae77Skettenis break;
288*b725ae77Skettenis }
289*b725ae77Skettenis off += 9;
290*b725ae77Skettenis
291*b725ae77Skettenis /* Extract thread id and sync object pointer. */
292*b725ae77Skettenis if (strlen (&buffer[off]) != 2 * 8 + 2
293*b725ae77Skettenis || buffer[off + 8] != ','
294*b725ae77Skettenis || buffer[off + 17] != ';')
295*b725ae77Skettenis {
296*b725ae77Skettenis bad_packet ();
297*b725ae77Skettenis break;
298*b725ae77Skettenis }
299*b725ae77Skettenis
300*b725ae77Skettenis buffer[off + 8] = '\0';
301*b725ae77Skettenis buffer[off + 17] = '\0';
302*b725ae77Skettenis
303*b725ae77Skettenis /* Display the result. */
304*b725ae77Skettenis (*gdb_kod_display) (sync_ids[i]);
305*b725ae77Skettenis (*gdb_kod_display) ("\t");
306*b725ae77Skettenis (*gdb_kod_display) (&buffer[off]);
307*b725ae77Skettenis (*gdb_kod_display) ("\t");
308*b725ae77Skettenis (*gdb_kod_display) (&buffer[off + 9]);
309*b725ae77Skettenis (*gdb_kod_display) ("\n");
310*b725ae77Skettenis }
311*b725ae77Skettenis }
312*b725ae77Skettenis
313*b725ae77Skettenis /* Free memory. */
314*b725ae77Skettenis for (i = 0; i < sync_next; ++i)
315*b725ae77Skettenis xfree (sync_ids[i]);
316*b725ae77Skettenis xfree (sync_ids);
317*b725ae77Skettenis }
318