Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | // ========== Copyright Header Begin ========================================== |
2 | // | |
3 | // OpenSPARC T2 Processor File: remote.cc | |
4 | // Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. | |
5 | // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES. | |
6 | // | |
7 | // The above named program is free software; you can redistribute it and/or | |
8 | // modify it under the terms of the GNU General Public | |
9 | // License version 2 as published by the Free Software Foundation. | |
10 | // | |
11 | // The above named program is distributed in the hope that it will be | |
12 | // useful, but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | // General Public License for more details. | |
15 | // | |
16 | // You should have received a copy of the GNU General Public | |
17 | // License along with this work; if not, write to the Free Software | |
18 | // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. | |
19 | // | |
20 | // ========== Copyright Header End ============================================ | |
21 | ///////////////////////////////////////////////////////////////////// | |
22 | // | |
23 | // FIle: remote.cc | |
24 | // | |
25 | // Copyright (C) 2005 Sun Microsystems, Inc. | |
26 | // All rights reserved. | |
27 | // | |
28 | ||
29 | ||
30 | // | |
31 | // Frontend socket interface for the debugger | |
32 | // | |
33 | ||
34 | ||
35 | ||
36 | ||
37 | ||
38 | ||
39 | #include <sys/types.h> | |
40 | #include <sys/socket.h> | |
41 | #include <sys/conf.h> | |
42 | #include <stropts.h> | |
43 | #include <signal.h> | |
44 | #include <netinet/in.h> | |
45 | #include <sys/un.h> | |
46 | #include <arpa/inet.h> | |
47 | #include <netdb.h> | |
48 | #include <stdio.h> | |
49 | #include <unistd.h> | |
50 | #include <fcntl.h> | |
51 | #include <string.h> /* for memset in FD_ZERO */ | |
52 | #include <errno.h> | |
53 | #include <thread.h> | |
54 | #include <stdlib.h> | |
55 | ||
56 | #include <assert.h> | |
57 | ||
58 | #include "types.h" | |
59 | #include "cpu_interface.h" | |
60 | #include "remote.h" | |
61 | ||
62 | // output debug log messages | |
63 | int g_debug_on = 1; | |
64 | #define DEBUG(s) if(g_debug_on){s} | |
65 | ||
66 | #define SWAP_BIT_5_0(I) ((( (I) & 0x01e ) | ( ((I) & 0x020) >> 5 )) & 0x1f) | |
67 | ||
68 | ||
69 | const int FOREVER = 1; | |
70 | ||
71 | // command delimiters | |
72 | const char START_CHR = '$'; | |
73 | const char END_CHR = '#'; | |
74 | ||
75 | ||
76 | ||
77 | typedef enum INSTATE | |
78 | { | |
79 | UNATTACHED, | |
80 | STOPPED, | |
81 | RUNNING | |
82 | ||
83 | } state_t; | |
84 | ||
85 | ||
86 | ||
87 | const int MAX_BUF_SIZE = 8192; | |
88 | ||
89 | ||
90 | ||
91 | ||
92 | // external routines called from this module | |
93 | extern int cpu_set_breakpoint ( int cpu_id, VCPU_BpType type, uint64_t addr ); | |
94 | extern int cpu_remove_breakpoint ( int cpu_id, VCPU_BpType type, uint64_t addr ); | |
95 | ||
96 | extern void UI_exec_cmd ( char *cmd ); | |
97 | ||
98 | ||
99 | // Convert number NIB to a hex digit. | |
100 | static int tohex (int nib) | |
101 | { | |
102 | if (nib < 10) | |
103 | return '0' + nib; | |
104 | else | |
105 | return 'a' + nib - 10; | |
106 | } | |
107 | ||
108 | ||
109 | // Convert hex digit A to a number. | |
110 | static int fromhex (uint8_t a) | |
111 | { | |
112 | int value = 0; | |
113 | if (a >= '0' && a <= '9') | |
114 | value = a - '0'; | |
115 | else if (a >= 'a' && a <= 'f') | |
116 | value = a - 'a' + 10; | |
117 | else if (a >= 'A' && a <= 'F') | |
118 | value = a - 'A' + 10; | |
119 | else | |
120 | printf ("Reply contains invalid hex digit %d", a); | |
121 | ||
122 | return value & 0xf; | |
123 | } | |
124 | ||
125 | // read next parameter from the command string; | |
126 | // return param value; | |
127 | // set string pointer to the next param | |
128 | static uint64_t read_next_param ( uint8_t **p ) | |
129 | { | |
130 | uint64_t value = 0; | |
131 | ||
132 | if (p != NULL) | |
133 | { | |
134 | // remove all spaces | |
135 | while((*p)[0] == ' ') | |
136 | (*p)++; | |
137 | ||
138 | ||
139 | for (int i=0; i<100; i++) | |
140 | { | |
141 | uint8_t c = (*p)[i]; | |
142 | if (c == '#' || c == '\0') | |
143 | { | |
144 | // last character | |
145 | *p = NULL; | |
146 | break; | |
147 | } | |
148 | else if (c == ',' || c == ':' || c == ' ') | |
149 | { | |
150 | // end of parameter | |
151 | (*p)+=i+1; | |
152 | break; | |
153 | } | |
154 | else | |
155 | { | |
156 | // convert from hex | |
157 | value = (value<<4) | fromhex(c); | |
158 | } | |
159 | } | |
160 | } | |
161 | ||
162 | return value; | |
163 | } | |
164 | ||
165 | static uint64_t get_value | |
166 | ( | |
167 | uint8_t **buf, // buffer to get value from | |
168 | int size // size of the value | |
169 | ) | |
170 | { | |
171 | assert( size <= 8 ); | |
172 | ||
173 | int i = 0; | |
174 | uint64_t value = 0; | |
175 | ||
176 | for (int offset = size * 8 - 4; offset>=0; offset -= 4) | |
177 | value = value | fromhex ( (*buf)[i++] ) << offset; | |
178 | ||
179 | *buf += i; // update buffer pointer | |
180 | ||
181 | return value; | |
182 | } | |
183 | ||
184 | ||
185 | ||
186 | static void put_value | |
187 | ( | |
188 | uint8_t **buf, // buffer to put a hex string value | |
189 | uint64_t val, // value | |
190 | int size // number of bytes ( should less or equal 8 ) | |
191 | ) | |
192 | { | |
193 | assert( size <= 8 ); | |
194 | int i = 0; | |
195 | for (int offset = size * 8 - 4; offset>=0; offset -= 4) | |
196 | { | |
197 | (*buf)[i++] = uint8_t( tohex (int(val >> offset)&0xf )); | |
198 | } | |
199 | *buf += i; // update the buffer pointer | |
200 | } | |
201 | ||
202 | ||
203 | ||
204 | ||
205 | ||
206 | ||
207 | class SocketInterface | |
208 | { | |
209 | ||
210 | public: | |
211 | ||
212 | int id; // connection id | |
213 | ||
214 | SocketInterface *next; | |
215 | ||
216 | int socket; | |
217 | state_t state; | |
218 | ||
219 | thread_t thread_id; | |
220 | ||
221 | int cpu_id; // current cpu id | |
222 | ||
223 | ||
224 | uint64_t symtab_base; | |
225 | char * symtab_fname; | |
226 | ||
227 | ||
228 | // communication buffers | |
229 | uint8_t send_buffer[MAX_BUF_SIZE]; | |
230 | uint8_t recv_buffer[MAX_BUF_SIZE]; | |
231 | ||
232 | ||
233 | public: | |
234 | ||
235 | SocketInterface () | |
236 | { | |
237 | id = 0; | |
238 | next = NULL; | |
239 | state = UNATTACHED; | |
240 | thread_id = 0; | |
241 | cpu_id = 0; | |
242 | ||
243 | } | |
244 | ||
245 | ~SocketInterface () { close(socket); } | |
246 | ||
247 | ||
248 | // send an ack - command was recieved | |
249 | void reply_ack () | |
250 | { | |
251 | uint8_t ack[4] = {'+',0}; | |
252 | DEBUG( printf("send an ack : + ; "); ); | |
253 | write( socket, ack, 1); | |
254 | } | |
255 | ||
256 | void reply_nack () | |
257 | { | |
258 | uint8_t nack[4] = {'-',0}; | |
259 | DEBUG( printf("send a nack : -\n"); ); | |
260 | write( socket, nack, 1); | |
261 | } | |
262 | ||
263 | void reply_ok () | |
264 | { | |
265 | send_buffer[1] = 'O'; | |
266 | send_buffer[2] = 'K'; | |
267 | this->send(3); | |
268 | } | |
269 | ||
270 | void reply_not_implemented () | |
271 | { | |
272 | this->send(0); | |
273 | } | |
274 | ||
275 | ||
276 | // send error number in hex | |
277 | void reply_error ( uint32_t error_number ) | |
278 | { | |
279 | send_buffer[1] = 'E'; | |
280 | send_buffer[2] = tohex ((error_number >> 4) & 0xf); | |
281 | send_buffer[3] = tohex (error_number & 0xf); | |
282 | this->send (4); | |
283 | ||
284 | } | |
285 | ||
286 | ||
287 | // send target stop reason in hex | |
288 | void reply_target_stopped (uint32_t reason) | |
289 | { | |
290 | send_buffer[1] = 'S'; | |
291 | send_buffer[2] = tohex ((reason >> 4) & 0xf); | |
292 | send_buffer[3] = tohex (reason & 0xf); | |
293 | this->send (4); | |
294 | ||
295 | } | |
296 | ||
297 | ||
298 | // send a data from the send_buffer; | |
299 | // add first, last control symbols and a checksum | |
300 | int send ( int size ) | |
301 | { | |
302 | int n = 0; | |
303 | ||
304 | // first control char | |
305 | send_buffer[n++] = START_CHR; | |
306 | uint8_t check_sum = 0; | |
307 | ||
308 | while (n<size) | |
309 | { | |
310 | if ( n > MAX_BUF_SIZE-3 ) | |
311 | return -1; | |
312 | ||
313 | uint8_t c = send_buffer[n]; | |
314 | ||
315 | // check null terminated | |
316 | if ( c == '\0') | |
317 | break; | |
318 | ||
319 | check_sum += c; | |
320 | n++; | |
321 | } | |
322 | // insert end control char | |
323 | send_buffer[n++] = END_CHR; | |
324 | ||
325 | // insert a check sum | |
326 | send_buffer[n++] = tohex ((check_sum >> 4) & 0xf); | |
327 | send_buffer[n++] = tohex (check_sum & 0xf); | |
328 | send_buffer[n] = 0; // null terminate | |
329 | ||
330 | DEBUG( printf("\n intf %d send a reply :%s \n", id, send_buffer); ); | |
331 | ||
332 | uint64_t res = write( socket, send_buffer, n); | |
333 | ||
334 | return (res != n) ? -1 : 0; | |
335 | } | |
336 | ||
337 | ||
338 | ||
339 | ||
340 | // read a command into recieve buffer; | |
341 | // overwrite a previous command if it was there; | |
342 | // return the number of bytes read,-1 if error | |
343 | int recv () | |
344 | { | |
345 | uint8_t c; | |
346 | int n = 0; | |
347 | int packet_started = 0; | |
348 | ||
349 | while ( n < MAX_BUF_SIZE ) | |
350 | { | |
351 | // read one character | |
352 | if ( read (socket, &c, 1) == 1 ) | |
353 | { | |
354 | // one character recieved | |
355 | if ( c == START_CHR) | |
356 | { | |
357 | // begin a new command | |
358 | n = 0; | |
359 | packet_started = 1; | |
360 | continue; | |
361 | } | |
362 | if ( c == END_CHR) | |
363 | { | |
364 | // last character in the command | |
365 | recv_buffer[n] = 0; // null terminated | |
366 | return n; | |
367 | } | |
368 | ||
369 | // accumulate the characters | |
370 | if (packet_started) | |
371 | { | |
372 | recv_buffer[n] = c; | |
373 | } | |
374 | n++; | |
375 | } | |
376 | } | |
377 | ||
378 | return (-1); // data is incomplete | |
379 | } | |
380 | ||
381 | // read one register value from the recieve buffer | |
382 | int read_reg () | |
383 | { | |
384 | ||
385 | uint8_t *args = recv_buffer+1; | |
386 | int reg_idx = (int)read_next_param ( &args ); | |
387 | ||
388 | ||
389 | uint8_t *sbuf = send_buffer+1; // skip first control char | |
390 | uint64_t value = 0; | |
391 | int size = 8; | |
392 | ||
393 | // read 8 byte gpr value | |
394 | if (reg_idx < 32) | |
395 | { | |
396 | g_vcpu[cpu_id]->get_reg(VCPU_IRF_0 + reg_idx, &value); | |
397 | put_value( &sbuf, value, 8); | |
398 | } | |
399 | else if (reg_idx < 64) // read 4 byte fpr value | |
400 | { | |
401 | g_vcpu[cpu_id]->get_reg(VCPU_FRF_0 + reg_idx - 32, &value); | |
402 | put_value( &sbuf, value, 4); | |
403 | } | |
404 | else if (reg_idx < 80) // read 8 byte fpr value | |
405 | { | |
406 | g_vcpu[cpu_id]->get_reg(VCPU_DRF_0 + reg_idx - 64 + 16, &value); | |
407 | put_value( &sbuf, value, 8); | |
408 | } | |
409 | else if (reg_idx < 90) // read control reg value | |
410 | { | |
411 | switch(reg_idx) | |
412 | { | |
413 | case 80: g_vcpu[cpu_id]->get_reg(VCPU_ASR_PC, &value); break; | |
414 | case 81: g_vcpu[cpu_id]->get_reg(VCPU_ASR_NPC, &value); break; | |
415 | case 82: g_vcpu[cpu_id]->get_reg(VCPU_PR_PSTATE, &value); break; | |
416 | case 83: g_vcpu[cpu_id]->get_reg(VCPU_ASR_FSR, &value); break; | |
417 | case 84: g_vcpu[cpu_id]->get_reg(VCPU_ASR_FPRS, &value); break; | |
418 | case 85: g_vcpu[cpu_id]->get_reg(VCPU_ASR_Y, &value); break; | |
419 | case 86: g_vcpu[cpu_id]->get_reg(VCPU_PR_CWP, &value); break; | |
420 | case 87: g_vcpu[cpu_id]->get_reg(VCPU_PR_PSTATE, &value); break; | |
421 | case 88: g_vcpu[cpu_id]->get_reg(VCPU_ASR_ASI, &value); break; | |
422 | case 89: g_vcpu[cpu_id]->get_reg(VCPU_ASR_CCR, &value); break; | |
423 | } | |
424 | put_value( &sbuf, value, 8); | |
425 | } | |
426 | else if (reg_idx < 122) // read 8 byte fpr value | |
427 | { | |
428 | g_vcpu[cpu_id]->get_reg(VCPU_DRF_0 + reg_idx - 90, &value); | |
429 | put_value( &sbuf, value, 8); | |
430 | } | |
431 | else if (reg_idx < 138) // read 16 byte fpr value | |
432 | { | |
433 | int regnum = (reg_idx - 122) * 2; | |
434 | g_vcpu[cpu_id]->get_reg(VCPU_DRF_0 + regnum, &value); | |
435 | put_value( &sbuf, value, 8); | |
436 | g_vcpu[cpu_id]->get_reg(VCPU_DRF_0 + regnum + 1, &value); | |
437 | put_value( &sbuf, value, 8); | |
438 | } | |
439 | else | |
440 | { | |
441 | reply_error (0); | |
442 | return 1; | |
443 | } | |
444 | ||
445 | int msg_size = int(sbuf - send_buffer); | |
446 | send(msg_size); | |
447 | return 0; | |
448 | ||
449 | } | |
450 | ||
451 | int read_all_regs () | |
452 | { | |
453 | uint8_t *sbuf = send_buffer+1; // skip first control char | |
454 | ||
455 | // read all GPRs | |
456 | for (int i=0; i<32; i++) | |
457 | { | |
458 | uint64_t gpr; | |
459 | g_vcpu[cpu_id]->get_reg(VCPU_IRF_0 + i, &gpr); | |
460 | put_value( &sbuf, gpr, 8); | |
461 | } | |
462 | ||
463 | // read all 32 bit fp regs | |
464 | for (int i=0; i<32; i++) | |
465 | { | |
466 | uint64_t fpr = 0; | |
467 | g_vcpu[cpu_id]->get_reg(VCPU_FRF_0 + i, &fpr); | |
468 | put_value( &sbuf, fpr, 4); | |
469 | } | |
470 | ||
471 | // read all 64 bit fp regs | |
472 | for (int i=32; i<64; i+=2) | |
473 | { | |
474 | // swap bit 5 and 0 | |
475 | uint64_t dfpr = 0; | |
476 | g_vcpu[cpu_id]->get_reg(VCPU_DRF_0 + (i / 2), &dfpr); | |
477 | put_value( &sbuf, dfpr, 8); | |
478 | } | |
479 | ||
480 | // read control registers | |
481 | uint64_t reg; | |
482 | g_vcpu[cpu_id]->get_reg(VCPU_ASR_PC, ®); | |
483 | put_value( &sbuf, reg, 8); | |
484 | ||
485 | g_vcpu[cpu_id]->get_reg(VCPU_ASR_NPC, ®); | |
486 | put_value( &sbuf, reg, 8); | |
487 | ||
488 | g_vcpu[cpu_id]->get_reg(VCPU_PR_PSTATE, ®); | |
489 | put_value( &sbuf, reg, 8); | |
490 | ||
491 | g_vcpu[cpu_id]->get_reg(VCPU_ASR_FSR, ®); | |
492 | put_value( &sbuf, reg, 8); | |
493 | ||
494 | g_vcpu[cpu_id]->get_reg(VCPU_ASR_FPRS, ®); | |
495 | put_value( &sbuf, reg, 8); | |
496 | ||
497 | g_vcpu[cpu_id]->get_reg(VCPU_ASR_Y, ®); | |
498 | put_value( &sbuf, reg, 8); | |
499 | ||
500 | int msg_size = int(sbuf - send_buffer); | |
501 | send(msg_size); | |
502 | return 0; | |
503 | } | |
504 | ||
505 | ||
506 | int write_all_regs () | |
507 | { | |
508 | uint64_t reg; | |
509 | uint8_t *buf = recv_buffer; | |
510 | ||
511 | // write all GPRs | |
512 | for (int i=0; i<32; i++) | |
513 | { | |
514 | reg = get_value( &buf, 8); | |
515 | g_vcpu[cpu_id]->set_reg(VCPU_IRF_0 + i, reg); | |
516 | } | |
517 | ||
518 | // write all 32 bit fp regs | |
519 | for (int i=0; i<32; i++) | |
520 | { | |
521 | reg = get_value( &buf, 4); | |
522 | g_vcpu[cpu_id]->set_reg(VCPU_FRF_0 + i, reg); | |
523 | } | |
524 | ||
525 | // write all 64 bit fp regs | |
526 | for (int i=32; i<64; i+=2) | |
527 | { | |
528 | reg = get_value( &buf, 8); | |
529 | g_vcpu[cpu_id]->set_reg(VCPU_DRF_0 + (i / 2), reg); | |
530 | } | |
531 | ||
532 | // write control registers | |
533 | reg = get_value( &buf, 8); | |
534 | g_vcpu[cpu_id]->set_reg(VCPU_ASR_PC, reg); | |
535 | ||
536 | reg = get_value( &buf, 8); | |
537 | g_vcpu[cpu_id]->set_reg(VCPU_ASR_NPC, reg); | |
538 | ||
539 | reg = get_value( &buf, 8); | |
540 | g_vcpu[cpu_id]->set_reg(VCPU_PR_PSTATE, reg); | |
541 | ||
542 | reg = get_value( &buf, 8); | |
543 | g_vcpu[cpu_id]->set_reg(VCPU_ASR_FSR, reg); | |
544 | ||
545 | reg = get_value( &buf, 8); | |
546 | g_vcpu[cpu_id]->set_reg(VCPU_ASR_FPRS, reg); | |
547 | ||
548 | reg = get_value( &buf, 8); | |
549 | g_vcpu[cpu_id]->set_reg(VCPU_ASR_Y, reg); | |
550 | ||
551 | return 0; | |
552 | } | |
553 | ||
554 | int read_mem () | |
555 | { | |
556 | uint8_t *args = recv_buffer+1; | |
557 | uint64_t addr = read_next_param ( &args ); | |
558 | int size = (int)read_next_param ( &args ); | |
559 | ||
560 | if (size <= 0) | |
561 | { | |
562 | reply_error (0); | |
563 | return 1; | |
564 | } | |
565 | ||
566 | if (size > MAX_BUF_SIZE-3) | |
567 | { | |
568 | size = MAX_BUF_SIZE-3; | |
569 | } | |
570 | ||
571 | uint8_t *sbuf = send_buffer+1; | |
572 | ||
573 | ||
574 | // read from the double word aligned address | |
575 | uint64_t addr8 = addr & ~uint64_t(7); | |
576 | uint64_t value = 0; | |
577 | if ( g_vcpu[cpu_id]->read_mem(addr8, &value, 8) != 0 ) | |
578 | { | |
579 | reply_error (1); | |
580 | return 1; | |
581 | } | |
582 | DEBUG( printf(" read dword %llx from address %llx \n", value, addr8); ); | |
583 | ||
584 | // alignement for the very first byte | |
585 | int start_byte_idx = int(addr & 0x7); | |
586 | int end_byte_idx = start_byte_idx + size-1; | |
587 | if (end_byte_idx>7) | |
588 | end_byte_idx = 7; | |
589 | int chunck_size = end_byte_idx - start_byte_idx + 1; | |
590 | ||
591 | ||
592 | if (end_byte_idx<7) | |
593 | value >>= ((7-end_byte_idx)*8); | |
594 | if (chunck_size<8) | |
595 | value &= ((uint64_t(1)<<(chunck_size*8))-1); | |
596 | ||
597 | put_value( &sbuf, value, chunck_size); | |
598 | ||
599 | int msg_size = int(sbuf - send_buffer); | |
600 | send( msg_size ); | |
601 | ||
602 | return 0; | |
603 | } | |
604 | ||
605 | int write_mem() | |
606 | { | |
607 | uint8_t *args = recv_buffer+1; | |
608 | ||
609 | uint64_t addr = read_next_param ( &args ); | |
610 | int size = (int)read_next_param ( &args ); | |
611 | ||
612 | // allow only double word aligned addresses | |
613 | if ((size <= 0) || ( addr & 0x7 ) ) | |
614 | { | |
615 | reply_error (0); | |
616 | return 1; | |
617 | } | |
618 | ||
619 | for (int i=0; i<size/8; i++) | |
620 | { | |
621 | // double word aligned address | |
622 | addr = ( addr + i*8 ) & ~uint64_t(7); | |
623 | ||
624 | uint64_t value = get_value ( &args ,size ); | |
625 | if (g_vcpu[cpu_id]->write_mem(addr, value, 8) != 0) | |
626 | { | |
627 | reply_error (1); | |
628 | return 1; | |
629 | } | |
630 | ||
631 | } | |
632 | ||
633 | ||
634 | reply_ok (); | |
635 | return 0; | |
636 | } | |
637 | ||
638 | int set_break () | |
639 | { | |
640 | ||
641 | uint8_t *args = recv_buffer+1; | |
642 | ||
643 | int type = (int)read_next_param ( &args ); | |
644 | uint64_t addr = read_next_param ( &args ); | |
645 | int size = (int)read_next_param ( &args ); | |
646 | ||
647 | switch (type) | |
648 | { | |
649 | case 0: // sw breakpoint | |
650 | case 1: // hw breakpoint | |
651 | ||
652 | if (cpu_set_breakpoint(cpu_id, VCPU_BP_INSTR_ADDR, addr) != 0) | |
653 | { | |
654 | reply_error(1); | |
655 | return 1; | |
656 | } | |
657 | break; | |
658 | ||
659 | case 2: // write watchpoint | |
660 | ||
661 | if (cpu_set_breakpoint(cpu_id, VCPU_BP_DATA_WRITE_ADDR, addr) != 0) | |
662 | { | |
663 | reply_error(1); | |
664 | return 1; | |
665 | } | |
666 | ||
667 | break; | |
668 | ||
669 | case 3: // read watchpoint | |
670 | ||
671 | if (cpu_set_breakpoint(cpu_id, VCPU_BP_DATA_READ_ADDR, addr) != 0) | |
672 | { | |
673 | reply_error(1); | |
674 | return 1; | |
675 | } | |
676 | break; | |
677 | ||
678 | default: | |
679 | reply_error (0); | |
680 | return 1; | |
681 | } | |
682 | ||
683 | ||
684 | reply_ok (); | |
685 | return 0; | |
686 | ||
687 | } | |
688 | ||
689 | int remove_break () | |
690 | { | |
691 | uint8_t *args = recv_buffer+1; | |
692 | ||
693 | int type = (int)read_next_param ( &args ); | |
694 | uint64_t addr = read_next_param ( &args ); | |
695 | int size = (int)read_next_param ( &args ); | |
696 | ||
697 | switch (type) | |
698 | { | |
699 | case 0: // sw breakpoint | |
700 | case 1: // hw breakpoint | |
701 | ||
702 | if (cpu_remove_breakpoint(cpu_id, VCPU_BP_INSTR_ADDR, addr) != 0) | |
703 | { | |
704 | //reply_error(1); | |
705 | return 1; | |
706 | } | |
707 | break; | |
708 | ||
709 | case 2: // write watchpoint | |
710 | ||
711 | if (cpu_remove_breakpoint(cpu_id, VCPU_BP_DATA_WRITE_ADDR, addr) != 0) | |
712 | { | |
713 | //reply_error(1); | |
714 | return 1; | |
715 | } | |
716 | ||
717 | break; | |
718 | ||
719 | case 3: // read watchpoint | |
720 | ||
721 | if (cpu_remove_breakpoint(cpu_id, VCPU_BP_DATA_READ_ADDR, addr) != 0) | |
722 | { | |
723 | //reply_error(1); | |
724 | return 1; | |
725 | } | |
726 | break; | |
727 | ||
728 | default: | |
729 | reply_error (0); | |
730 | return 1; | |
731 | ||
732 | } | |
733 | ||
734 | reply_ok (); | |
735 | return 0; | |
736 | } | |
737 | ||
738 | ||
739 | }; | |
740 | ||
741 | ||
742 | // head of linked list of interface objects | |
743 | SocketInterface * gpIntf; | |
744 | ||
745 | ||
746 | // This routine is called when target is stoped. | |
747 | // Inform the debugger about the reason of stopping. | |
748 | int target_stopped ( int reason ) | |
749 | { | |
750 | SocketInterface *in = gpIntf; | |
751 | ||
752 | // for all attached remote interfaces | |
753 | while ( in ) | |
754 | { | |
755 | if(in->state == RUNNING) | |
756 | { | |
757 | in->reply_target_stopped (reason); | |
758 | in->state = STOPPED; | |
759 | } | |
760 | ||
761 | in = in->next; | |
762 | } | |
763 | return 0; | |
764 | } | |
765 | ||
766 | ||
767 | ||
768 | ||
769 | ||
770 | ||
771 | // This new thread is invoked once contact with a debugger is | |
772 | // been established. This thread exits once that debugger | |
773 | // connection vanishes. | |
774 | // Any one debugger can stop the simulation, all are required | |
775 | // to be active to continue simulation. | |
776 | ||
777 | extern "C" | |
778 | void * in_worker_thread (void * argp) | |
779 | { | |
780 | ||
781 | SocketInterface *in = (SocketInterface *)argp; | |
782 | ||
783 | // run the command interface until we get the | |
784 | // command to termnate this session | |
785 | ||
786 | while (FOREVER) | |
787 | { | |
788 | ||
789 | // get the command packet | |
790 | int csize = in->recv(); | |
791 | ||
792 | if ( csize <= 0) | |
793 | { | |
794 | printf ("failed in communication"); | |
795 | in->reply_nack(); // send a nack | |
796 | continue; | |
797 | } | |
798 | ||
799 | // send an ack | |
800 | in->reply_ack(); | |
801 | ||
802 | DEBUG( printf(" remote interface %d got a command %s: ", in->id, in->recv_buffer); ); | |
803 | ||
804 | char command = in->recv_buffer[0]; | |
805 | ||
806 | switch ( command ) | |
807 | { | |
808 | ||
809 | case '?': // why stopped | |
810 | DEBUG( printf("get the the reason why stoped \n"); ); | |
811 | ||
812 | in->reply_target_stopped (0); | |
813 | break; | |
814 | ||
815 | ||
816 | case 'p': // read register | |
817 | DEBUG( printf("read register :%s \n", in->recv_buffer+1); ); | |
818 | in->read_reg (); | |
819 | //in->reply_not_implemented(); // not implemented | |
820 | break; | |
821 | ||
822 | case 'g': // read all registers | |
823 | { | |
824 | DEBUG( printf("read all register \n" ); ); | |
825 | ||
826 | in->read_all_regs (); | |
827 | ||
828 | break; | |
829 | } | |
830 | ||
831 | case 'G': // write registers | |
832 | { | |
833 | DEBUG( printf("write registers: %s\n", in->recv_buffer+1); ); | |
834 | ||
835 | in->write_all_regs(); | |
836 | ||
837 | in->reply_ok(); | |
838 | break; | |
839 | } | |
840 | ||
841 | case 'm': // read memory | |
842 | { | |
843 | ||
844 | DEBUG( printf("read memory : %s \n", in->recv_buffer+1); ); | |
845 | ||
846 | in->read_mem(); | |
847 | break; | |
848 | } | |
849 | case 'M': // write memory | |
850 | { | |
851 | DEBUG( printf("write memory :%s \n", in->recv_buffer+1); ); | |
852 | ||
853 | in->write_mem(); | |
854 | break; | |
855 | } | |
856 | ||
857 | case 'c': // continue from address | |
858 | DEBUG( printf("continue %s \n", in->recv_buffer+1); ); | |
859 | in->state = RUNNING; | |
860 | UI_exec_cmd("run\n"); | |
861 | break; | |
862 | ||
863 | case 's': // step from address | |
864 | DEBUG( printf("step :%s \n", in->recv_buffer+1); ); | |
865 | in->state = RUNNING; | |
866 | UI_exec_cmd("stepi 1\n"); | |
867 | break; | |
868 | ||
869 | case 'z': // remove a breakpoint | |
870 | DEBUG( printf("remove a breakpoint :%s \n", in->recv_buffer+1); ); | |
871 | ||
872 | in->remove_break(); | |
873 | break; | |
874 | ||
875 | case 'Z': // set a breakpoint | |
876 | DEBUG( printf("set a breakpoint :%s \n", in->recv_buffer+1); ); | |
877 | ||
878 | in->set_break(); | |
879 | break; | |
880 | ||
881 | case 'k': // killed | |
882 | goto quit; | |
883 | ||
884 | case 'D': // detach the session | |
885 | goto quit; | |
886 | ||
887 | default: | |
888 | DEBUG( printf("\n unimplemented command %s \n", in->recv_buffer); ); | |
889 | in->reply_not_implemented(); // not implemented | |
890 | } | |
891 | } | |
892 | ||
893 | ||
894 | ||
895 | quit: | |
896 | ||
897 | // remove interface structure from the list | |
898 | SocketInterface *prev=NULL; | |
899 | for ( SocketInterface *p = gpIntf; | |
900 | p != NULL; | |
901 | prev = p, p = p->next ) | |
902 | { | |
903 | if (p == in) | |
904 | { | |
905 | if (prev) | |
906 | prev->next = in->next; | |
907 | else | |
908 | gpIntf = in->next; | |
909 | ||
910 | close (in->socket); | |
911 | delete in; | |
912 | break; | |
913 | } | |
914 | } | |
915 | ||
916 | ||
917 | thr_exit(NULL); | |
918 | ||
919 | return NULL; | |
920 | } | |
921 | ||
922 | ||
923 | ||
924 | ||
925 | ||
926 | ||
927 | ||
928 | ||
929 | ||
930 | ||
931 | ||
932 | ||
933 | // main program thread | |
934 | // to wait for user interface connections. | |
935 | extern "C" | |
936 | void *wait_connection (void *param) | |
937 | { | |
938 | static fd_set comm_channels; | |
939 | int tcp_attach_socket, res; | |
940 | struct sockaddr_in tcp_server; | |
941 | struct sockaddr_in from; | |
942 | int fromlen; | |
943 | int skt; | |
944 | int fh, length, on=1; | |
945 | int max_channel; | |
946 | sigset_t sigs; | |
947 | struct hostent * hp; | |
948 | char * froms; | |
949 | int retry_cnt=0; | |
950 | ||
951 | sigfillset(&sigs); | |
952 | thr_sigsetmask(SIG_BLOCK, &sigs, NULL); | |
953 | ||
954 | skt = socket(AF_INET, SOCK_STREAM, 0); | |
955 | if (skt < 0) | |
956 | { | |
957 | printf ("ERROR: cannot opening stream socket\n"); | |
958 | return NULL; | |
959 | } | |
960 | ||
961 | // enable the reuse of this socket if this process dies | |
962 | if (setsockopt(skt,SOL_SOCKET,SO_REUSEADDR,(char*)&on,int(sizeof(on)))<0) | |
963 | { | |
964 | printf ("ERROR: turning on REUSEADDR \n"); | |
965 | return NULL; | |
966 | } | |
967 | ||
968 | RemoteConfig *config = (RemoteConfig *)param; | |
969 | ||
970 | g_debug_on = config->debug_on; | |
971 | ||
972 | retry: // bind the connection | |
973 | ||
974 | tcp_server.sin_family = AF_INET; | |
975 | tcp_server.sin_addr.s_addr = INADDR_ANY; | |
976 | tcp_server.sin_port = config->port; | |
977 | ||
978 | retry_cnt++; | |
979 | printf("- trying port:%d", config->port); | |
980 | ||
981 | if (bind(skt, (struct sockaddr *)&tcp_server, int(sizeof(tcp_server))) < 0) | |
982 | { | |
983 | switch (errno) | |
984 | { | |
985 | case EAGAIN: | |
986 | goto retry; | |
987 | ||
988 | case EADDRINUSE: | |
989 | printf("\nPort %d already in use ", config->port); | |
990 | ||
991 | default: | |
992 | printf("ERROR: binding tcp stream socket"); | |
993 | return NULL; | |
994 | } | |
995 | } | |
996 | ||
997 | ||
998 | length = int(sizeof(tcp_server)); | |
999 | if (getsockname(skt, (struct sockaddr *) &tcp_server, &length)==-1) | |
1000 | { | |
1001 | printf("ERROR:getting socket name"); | |
1002 | return NULL; | |
1003 | } | |
1004 | ||
1005 | // start waiting for the connection | |
1006 | printf("\nWaiting for connection on port # %d\n",ntohs(tcp_server.sin_port)); | |
1007 | listen(skt, config->max_connections); | |
1008 | ||
1009 | tcp_attach_socket = skt; | |
1010 | max_channel = tcp_attach_socket; | |
1011 | FD_ZERO(&comm_channels); | |
1012 | FD_SET(tcp_attach_socket, &comm_channels); | |
1013 | ||
1014 | // Wait for a control connection | |
1015 | int next_connection = 0; | |
1016 | while(FOREVER) | |
1017 | { | |
1018 | ||
1019 | if (next_connection > config->max_connections - 1) | |
1020 | { | |
1021 | sleep (2); | |
1022 | continue; | |
1023 | } | |
1024 | ||
1025 | res = select(max_channel+1, &comm_channels, (fd_set*)0, (fd_set*)0, (struct timeval*)0 /* stall */); | |
1026 | if (res<0) | |
1027 | { | |
1028 | printf("ERROR: select"); | |
1029 | break; | |
1030 | } | |
1031 | ||
1032 | // accept the connection | |
1033 | fromlen = int(sizeof(from)); | |
1034 | fh = accept(tcp_attach_socket,(struct sockaddr *)&from, (int*)&fromlen); | |
1035 | ||
1036 | ||
1037 | hp = gethostbyaddr((char *)&from.sin_addr, 4, AF_INET); | |
1038 | if (hp == (struct hostent *)0) | |
1039 | { | |
1040 | froms = inet_ntoa(from.sin_addr); | |
1041 | fprintf(stderr,"cant resolve hostname for %s\n", froms);; | |
1042 | } | |
1043 | else | |
1044 | { | |
1045 | froms = hp->h_name; | |
1046 | } | |
1047 | printf("got remote connection from %s : port %d\n", froms, from.sin_port); | |
1048 | ||
1049 | // Create the thread to handle this debugger | |
1050 | // connection. It cleans up after itself | |
1051 | // if anything goes wrong | |
1052 | ||
1053 | SocketInterface *in = new SocketInterface (); | |
1054 | if (gpIntf == NULL) | |
1055 | { | |
1056 | gpIntf = in; | |
1057 | } | |
1058 | else | |
1059 | { | |
1060 | in->next = gpIntf; | |
1061 | gpIntf = in; | |
1062 | } | |
1063 | ||
1064 | in->id = next_connection; | |
1065 | next_connection++; | |
1066 | ||
1067 | in->socket = fh; | |
1068 | DEBUG( printf("connection %d on socket_id=%d\n", in->id, in->socket); ); | |
1069 | ||
1070 | ||
1071 | thr_create(NULL, NULL, in_worker_thread, (void*)in, THR_BOUND, &in->thread_id); | |
1072 | ||
1073 | }; // while forever | |
1074 | ||
1075 | ||
1076 | return NULL; | |
1077 | } | |
1078 | ||
1079 | ||
1080 | ||
1081 | int start_connection ( RemoteConfig *config ) | |
1082 | { | |
1083 | thread_t thread_id; | |
1084 | ||
1085 | ||
1086 | // start thread waiting for a remote connection | |
1087 | thr_create(NULL, NULL, wait_connection, (void *)config, THR_BOUND, &thread_id); | |
1088 | ||
1089 | printf ( "remote debug server started...\n"); | |
1090 | ||
1091 | return 0; | |
1092 | ||
1093 | } | |
1094 | ||
1095 | int destroy_connection () | |
1096 | { | |
1097 | SocketInterface *in = gpIntf; | |
1098 | ||
1099 | // for all attached remote interfaces | |
1100 | while ( in ) | |
1101 | { | |
1102 | in->reply_target_stopped (SIGNAL_HUP); | |
1103 | SocketInterface *p = in; | |
1104 | in = in->next; | |
1105 | delete in; | |
1106 | } | |
1107 | return 0; | |
1108 | } | |
1109 | ||
1110 | ||
1111 | //////////////////////////////////////////////////////// | |
1112 | // | |
1113 | // Get exported interface from the Remote shared library. | |
1114 | // | |
1115 | // Assign function pointers in the interface structure. | |
1116 | // | |
1117 | // | |
1118 | // return: 0 - success; 1 - fail; | |
1119 | ||
1120 | int get_ex_remote_interface | |
1121 | ( | |
1122 | RemoteExInterface *intf // pointer to the interface structure | |
1123 | ) | |
1124 | { | |
1125 | intf->create = start_connection; | |
1126 | intf->destroy = destroy_connection; | |
1127 | intf->update_status = target_stopped; | |
1128 | ||
1129 | return 0; | |
1130 | } | |
1131 | ||
1132 | ||
1133 | ||
1134 | ||
1135 | ||
1136 | ||
1137 | ||
1138 |