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