OLD | NEW |
(Empty) | |
| 1 /* GDB stub for Itanium OpenVMS |
| 2 Copyright (C) 2012 Free Software Foundation, Inc. |
| 3 |
| 4 Contributed by Tristan Gingold, AdaCore. |
| 5 |
| 6 This program is free software; you can redistribute it and/or modify |
| 7 it under the terms of the GNU General Public License as published by |
| 8 the Free Software Foundation; either version 3 of the License, or |
| 9 (at your option) any later version. |
| 10 |
| 11 This program is distributed in the hope that it will be useful, |
| 12 but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 GNU General Public License for more details. |
| 15 |
| 16 You should have received a copy of the GNU General Public License |
| 17 along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
| 18 |
| 19 /* On VMS, the debugger (in our case the stub) is loaded in the process and |
| 20 executed (via SYS$IMGSTA) before the main entry point of the executable. |
| 21 In UNIX parlance, this is like using LD_PRELOAD and debug via installing |
| 22 SIGTRAP, SIGSEGV... handlers. |
| 23 |
| 24 This is currently a partial implementation. In particular, modifying |
| 25 registers is currently not implemented, as well as inferior procedure |
| 26 calls. |
| 27 |
| 28 This is written in very low-level C, in order not to use the C runtime, |
| 29 because it may have weird consequences on the program being debugged. |
| 30 */ |
| 31 |
| 32 #if __INITIAL_POINTER_SIZE != 64 |
| 33 #error "Must be compiled with 64 bit pointers" |
| 34 #endif |
| 35 |
| 36 #define __NEW_STARLET 1 |
| 37 #include <descrip.h> |
| 38 #include <iledef.h> |
| 39 #include <efndef.h> |
| 40 #include <in.h> |
| 41 #include <inet.h> |
| 42 #include <iodef.h> |
| 43 #include <ssdef.h> |
| 44 #include <starlet.h> |
| 45 #include <stsdef.h> |
| 46 #include <tcpip$inetdef.h> |
| 47 |
| 48 #include <lib$routines.h> |
| 49 #include <ots$routines.h> |
| 50 #include <str$routines.h> |
| 51 #include <libdef.h> |
| 52 #include <clidef.h> |
| 53 #include <iosbdef.h> |
| 54 #include <dvidef.h> |
| 55 #include <lnmdef.h> |
| 56 #include <builtins.h> |
| 57 #include <prtdef.h> |
| 58 #include <psldef.h> |
| 59 #include <ssdef.h> |
| 60 #include <chfdef.h> |
| 61 |
| 62 #include <lib_c/imcbdef.h> |
| 63 #include <lib_c/ldrimgdef.h> |
| 64 #include <lib_c/intstkdef.h> |
| 65 #include <lib_c/psrdef.h> |
| 66 #include <lib_c/ifddef.h> |
| 67 #include <lib_c/eihddef.h> |
| 68 |
| 69 #include <stdarg.h> |
| 70 #include <pthread_debug.h> |
| 71 |
| 72 #define VMS_PAGE_SIZE 0x2000 |
| 73 #define VMS_PAGE_MASK (VMS_PAGE_SIZE - 1) |
| 74 |
| 75 /* Declared in lib$ots. */ |
| 76 extern void ots$fill (void *addr, size_t len, unsigned char b); |
| 77 extern void ots$move (void *dst, size_t len, const void *src); |
| 78 extern int ots$strcmp_eql (const void *str1, size_t str1len, |
| 79 const void *str2, size_t str2len); |
| 80 |
| 81 /* Stub port number. */ |
| 82 static unsigned int serv_port = 1234; |
| 83 |
| 84 /* DBGEXT structure. Not declared in any header. */ |
| 85 struct dbgext_control_block |
| 86 { |
| 87 unsigned short dbgext$w_function_code; |
| 88 #define DBGEXT$K_NEXT_TASK 3 |
| 89 #define DBGEXT$K_STOP_ALL_OTHER_TASKS 31 |
| 90 #define DBGEXT$K_GET_REGS 33 |
| 91 unsigned short dbgext$w_facility_id; |
| 92 #define CMA$_FACILITY 64 |
| 93 unsigned int dbgext$l_status; |
| 94 unsigned int dbgext$l_flags; |
| 95 unsigned int dbgext$l_print_routine; |
| 96 unsigned int dbgext$l_evnt_code; |
| 97 unsigned int dbgext$l_evnt_name; |
| 98 unsigned int dbgext$l_evnt_entry; |
| 99 unsigned int dbgext$l_task_value; |
| 100 unsigned int dbgext$l_task_number; |
| 101 unsigned int dbgext$l_ada_flags; |
| 102 unsigned int dbgext$l_stop_value; |
| 103 #define dbgext$l_priority dbgext$l_stop_value; |
| 104 #define dbgext$l_symb_addr dbgext$l_stop_value; |
| 105 #define dbgext$l_time_slice dbgext$l_stop_value; |
| 106 unsigned int dbgext$l_active_registers; |
| 107 }; |
| 108 |
| 109 #pragma pointer_size save |
| 110 #pragma pointer_size 32 |
| 111 |
| 112 /* Pthread handler. */ |
| 113 static int (*dbgext_func) (struct dbgext_control_block *blk); |
| 114 |
| 115 #pragma pointer_size restore |
| 116 |
| 117 /* Set to 1 if thread-aware. */ |
| 118 static int has_threads; |
| 119 |
| 120 /* Current thread. */ |
| 121 static pthread_t selected_thread; |
| 122 static pthreadDebugId_t selected_id; |
| 123 |
| 124 /* Internal debugging flags. */ |
| 125 struct debug_flag |
| 126 { |
| 127 /* Name of the flag (as a string descriptor). */ |
| 128 const struct dsc$descriptor_s name; |
| 129 /* Value. */ |
| 130 int val; |
| 131 }; |
| 132 |
| 133 /* Macro to define a debugging flag. */ |
| 134 #define DEBUG_FLAG_ENTRY(str) \ |
| 135 { { sizeof (str) - 1, DSC$K_DTYPE_T, DSC$K_CLASS_S, str }, 0} |
| 136 |
| 137 static struct debug_flag debug_flags[] = |
| 138 { |
| 139 /* Disp packets exchanged with gdb. */ |
| 140 DEBUG_FLAG_ENTRY("packets"), |
| 141 #define trace_pkt (debug_flags[0].val) |
| 142 /* Display entry point informations. */ |
| 143 DEBUG_FLAG_ENTRY("entry"), |
| 144 #define trace_entry (debug_flags[1].val) |
| 145 /* Be verbose about exceptions. */ |
| 146 DEBUG_FLAG_ENTRY("excp"), |
| 147 #define trace_excp (debug_flags[2].val) |
| 148 /* Be verbose about unwinding. */ |
| 149 DEBUG_FLAG_ENTRY("unwind"), |
| 150 #define trace_unwind (debug_flags[3].val) |
| 151 /* Display image at startup. */ |
| 152 DEBUG_FLAG_ENTRY("images"), |
| 153 #define trace_images (debug_flags[4].val) |
| 154 /* Display pthread_debug info. */ |
| 155 DEBUG_FLAG_ENTRY("pthreaddbg") |
| 156 #define trace_pthreaddbg (debug_flags[5].val) |
| 157 }; |
| 158 |
| 159 #define NBR_DEBUG_FLAGS (sizeof (debug_flags) / sizeof (debug_flags[0])) |
| 160 |
| 161 /* Connect inet device I/O channel. */ |
| 162 static unsigned short conn_channel; |
| 163 |
| 164 /* Widely used hex digit to ascii. */ |
| 165 static const char hex[] = "0123456789abcdef"; |
| 166 |
| 167 /* Socket characteristics. Apparently, there are no declaration for it in |
| 168 standard headers. */ |
| 169 struct sockchar |
| 170 { |
| 171 unsigned short prot; |
| 172 unsigned char type; |
| 173 unsigned char af; |
| 174 }; |
| 175 |
| 176 /* Chain of images loaded. */ |
| 177 extern IMCB* ctl$gl_imglstptr; |
| 178 |
| 179 /* IA64 integer register representation. */ |
| 180 union ia64_ireg |
| 181 { |
| 182 unsigned __int64 v; |
| 183 unsigned char b[8]; |
| 184 }; |
| 185 |
| 186 /* IA64 register numbers, as defined by ia64-tdep.h. */ |
| 187 #define IA64_GR0_REGNUM 0 |
| 188 #define IA64_GR32_REGNUM (IA64_GR0_REGNUM + 32) |
| 189 |
| 190 /* Floating point registers; 128 82-bit wide registers. */ |
| 191 #define IA64_FR0_REGNUM 128 |
| 192 |
| 193 /* Predicate registers; There are 64 of these one bit registers. It'd |
| 194 be more convenient (implementation-wise) to use a single 64 bit |
| 195 word with all of these register in them. Note that there's also a |
| 196 IA64_PR_REGNUM below which contains all the bits and is used for |
| 197 communicating the actual values to the target. */ |
| 198 #define IA64_PR0_REGNUM 256 |
| 199 |
| 200 /* Branch registers: 8 64-bit registers for holding branch targets. */ |
| 201 #define IA64_BR0_REGNUM 320 |
| 202 |
| 203 /* Virtual frame pointer; this matches IA64_FRAME_POINTER_REGNUM in |
| 204 gcc/config/ia64/ia64.h. */ |
| 205 #define IA64_VFP_REGNUM 328 |
| 206 |
| 207 /* Virtual return address pointer; this matches |
| 208 IA64_RETURN_ADDRESS_POINTER_REGNUM in gcc/config/ia64/ia64.h. */ |
| 209 #define IA64_VRAP_REGNUM 329 |
| 210 |
| 211 /* Predicate registers: There are 64 of these 1-bit registers. We |
| 212 define a single register which is used to communicate these values |
| 213 to/from the target. We will somehow contrive to make it appear |
| 214 that IA64_PR0_REGNUM thru IA64_PR63_REGNUM hold the actual values. */ |
| 215 #define IA64_PR_REGNUM 330 |
| 216 |
| 217 /* Instruction pointer: 64 bits wide. */ |
| 218 #define IA64_IP_REGNUM 331 |
| 219 |
| 220 /* Process Status Register. */ |
| 221 #define IA64_PSR_REGNUM 332 |
| 222 |
| 223 /* Current Frame Marker (raw form may be the cr.ifs). */ |
| 224 #define IA64_CFM_REGNUM 333 |
| 225 |
| 226 /* Application registers; 128 64-bit wide registers possible, but some |
| 227 of them are reserved. */ |
| 228 #define IA64_AR0_REGNUM 334 |
| 229 #define IA64_KR0_REGNUM (IA64_AR0_REGNUM + 0) |
| 230 #define IA64_KR7_REGNUM (IA64_KR0_REGNUM + 7) |
| 231 |
| 232 #define IA64_RSC_REGNUM (IA64_AR0_REGNUM + 16) |
| 233 #define IA64_BSP_REGNUM (IA64_AR0_REGNUM + 17) |
| 234 #define IA64_BSPSTORE_REGNUM (IA64_AR0_REGNUM + 18) |
| 235 #define IA64_RNAT_REGNUM (IA64_AR0_REGNUM + 19) |
| 236 #define IA64_FCR_REGNUM (IA64_AR0_REGNUM + 21) |
| 237 #define IA64_EFLAG_REGNUM (IA64_AR0_REGNUM + 24) |
| 238 #define IA64_CSD_REGNUM (IA64_AR0_REGNUM + 25) |
| 239 #define IA64_SSD_REGNUM (IA64_AR0_REGNUM + 26) |
| 240 #define IA64_CFLG_REGNUM (IA64_AR0_REGNUM + 27) |
| 241 #define IA64_FSR_REGNUM (IA64_AR0_REGNUM + 28) |
| 242 #define IA64_FIR_REGNUM (IA64_AR0_REGNUM + 29) |
| 243 #define IA64_FDR_REGNUM (IA64_AR0_REGNUM + 30) |
| 244 #define IA64_CCV_REGNUM (IA64_AR0_REGNUM + 32) |
| 245 #define IA64_UNAT_REGNUM (IA64_AR0_REGNUM + 36) |
| 246 #define IA64_FPSR_REGNUM (IA64_AR0_REGNUM + 40) |
| 247 #define IA64_ITC_REGNUM (IA64_AR0_REGNUM + 44) |
| 248 #define IA64_PFS_REGNUM (IA64_AR0_REGNUM + 64) |
| 249 #define IA64_LC_REGNUM (IA64_AR0_REGNUM + 65) |
| 250 #define IA64_EC_REGNUM (IA64_AR0_REGNUM + 66) |
| 251 |
| 252 /* NAT (Not A Thing) Bits for the general registers; there are 128 of |
| 253 these. */ |
| 254 #define IA64_NAT0_REGNUM 462 |
| 255 |
| 256 /* Process registers when a condition is caught. */ |
| 257 struct ia64_all_regs |
| 258 { |
| 259 union ia64_ireg gr[32]; |
| 260 union ia64_ireg br[8]; |
| 261 union ia64_ireg ip; |
| 262 union ia64_ireg psr; |
| 263 union ia64_ireg bsp; |
| 264 union ia64_ireg cfm; |
| 265 union ia64_ireg pfs; |
| 266 union ia64_ireg pr; |
| 267 }; |
| 268 |
| 269 static struct ia64_all_regs excp_regs; |
| 270 static struct ia64_all_regs sel_regs; |
| 271 static pthread_t sel_regs_pthread; |
| 272 |
| 273 /* IO channel for the terminal. */ |
| 274 static unsigned short term_chan; |
| 275 |
| 276 /* Output buffer and length. */ |
| 277 static char term_buf[128]; |
| 278 static int term_buf_len; |
| 279 |
| 280 /* Buffer for communication with gdb. */ |
| 281 static unsigned char gdb_buf[sizeof (struct ia64_all_regs) * 2 + 64]; |
| 282 static unsigned int gdb_blen; |
| 283 |
| 284 /* Previous primary handler. */ |
| 285 static void *prevhnd; |
| 286 |
| 287 /* Entry point address and bundle. */ |
| 288 static unsigned __int64 entry_pc; |
| 289 static unsigned char entry_saved[16]; |
| 290 |
| 291 /* Write on the terminal. */ |
| 292 |
| 293 static void |
| 294 term_raw_write (const char *str, unsigned int len) |
| 295 { |
| 296 unsigned short status; |
| 297 struct _iosb iosb; |
| 298 |
| 299 status = sys$qiow (EFN$C_ENF, /* Event flag. */ |
| 300 term_chan, /* I/O channel. */ |
| 301 IO$_WRITEVBLK, /* I/O function code. */ |
| 302 &iosb, /* I/O status block. */ |
| 303 0, /* Ast service routine. */ |
| 304 0, /* Ast parameter. */ |
| 305 (char *)str, /* P1 - buffer address. */ |
| 306 len, /* P2 - buffer length. */ |
| 307 0, 0, 0, 0); |
| 308 |
| 309 if (status & STS$M_SUCCESS) |
| 310 status = iosb.iosb$w_status; |
| 311 if (!(status & STS$M_SUCCESS)) |
| 312 LIB$SIGNAL (status); |
| 313 } |
| 314 |
| 315 /* Flush ther term buffer. */ |
| 316 |
| 317 static void |
| 318 term_flush (void) |
| 319 { |
| 320 if (term_buf_len != 0) |
| 321 { |
| 322 term_raw_write (term_buf, term_buf_len); |
| 323 term_buf_len = 0; |
| 324 } |
| 325 } |
| 326 |
| 327 /* Write a single character, without translation. */ |
| 328 |
| 329 static void |
| 330 term_raw_putchar (char c) |
| 331 { |
| 332 if (term_buf_len == sizeof (term_buf)) |
| 333 term_flush (); |
| 334 term_buf[term_buf_len++] = c; |
| 335 } |
| 336 |
| 337 /* Write character C. Translate '\n' to '\n\r'. */ |
| 338 |
| 339 static void |
| 340 term_putc (char c) |
| 341 { |
| 342 if (c < 32) |
| 343 switch (c) |
| 344 { |
| 345 case '\r': |
| 346 case '\n': |
| 347 break; |
| 348 default: |
| 349 c = '.'; |
| 350 break; |
| 351 } |
| 352 term_raw_putchar (c); |
| 353 if (c == '\n') |
| 354 { |
| 355 term_raw_putchar ('\r'); |
| 356 term_flush (); |
| 357 } |
| 358 } |
| 359 |
| 360 /* Write a C string. */ |
| 361 |
| 362 static void |
| 363 term_puts (const char *str) |
| 364 { |
| 365 while (*str) |
| 366 term_putc (*str++); |
| 367 } |
| 368 |
| 369 /* Write LEN bytes from STR. */ |
| 370 |
| 371 static void |
| 372 term_write (const char *str, unsigned int len) |
| 373 { |
| 374 for (; len > 0; len--) |
| 375 term_putc (*str++); |
| 376 } |
| 377 |
| 378 /* Write using FAO formatting. */ |
| 379 |
| 380 static void |
| 381 term_fao (const char *str, unsigned int str_len, ...) |
| 382 { |
| 383 int cnt; |
| 384 va_list vargs; |
| 385 int i; |
| 386 __int64 *args; |
| 387 int status; |
| 388 struct dsc$descriptor_s dstr = |
| 389 { str_len, DSC$K_DTYPE_T, DSC$K_CLASS_S, (__char_ptr32)str }; |
| 390 char buf[128]; |
| 391 $DESCRIPTOR (buf_desc, buf); |
| 392 |
| 393 va_start (vargs, str_len); |
| 394 va_count (cnt); |
| 395 args = (__int64 *) __ALLOCA (cnt * sizeof (__int64)); |
| 396 cnt -= 2; |
| 397 for (i = 0; i < cnt; i++) |
| 398 args[i] = va_arg (vargs, __int64); |
| 399 |
| 400 status = sys$faol_64 (&dstr, &buf_desc.dsc$w_length, &buf_desc, args); |
| 401 if (status & 1) |
| 402 { |
| 403 /* FAO !/ already insert a line feed. */ |
| 404 for (i = 0; i < buf_desc.dsc$w_length; i++) |
| 405 { |
| 406 term_raw_putchar (buf[i]); |
| 407 if (buf[i] == '\n') |
| 408 term_flush (); |
| 409 } |
| 410 } |
| 411 |
| 412 va_end (vargs); |
| 413 } |
| 414 |
| 415 #define TERM_FAO(STR, ...) term_fao (STR, sizeof (STR) - 1, __VA_ARGS__) |
| 416 |
| 417 /* New line. */ |
| 418 |
| 419 static void |
| 420 term_putnl (void) |
| 421 { |
| 422 term_putc ('\n'); |
| 423 } |
| 424 |
| 425 /* Initialize terminal. */ |
| 426 |
| 427 static void |
| 428 term_init (void) |
| 429 { |
| 430 unsigned int status,i; |
| 431 unsigned short len; |
| 432 char resstring[LNM$C_NAMLENGTH]; |
| 433 static const $DESCRIPTOR (tabdesc, "LNM$FILE_DEV"); |
| 434 static const $DESCRIPTOR (logdesc, "SYS$OUTPUT"); |
| 435 $DESCRIPTOR (term_desc, resstring); |
| 436 ILE3 item_lst[2]; |
| 437 |
| 438 item_lst[0].ile3$w_length = LNM$C_NAMLENGTH; |
| 439 item_lst[0].ile3$w_code = LNM$_STRING; |
| 440 item_lst[0].ile3$ps_bufaddr = resstring; |
| 441 item_lst[0].ile3$ps_retlen_addr = &len; |
| 442 item_lst[1].ile3$w_length = 0; |
| 443 item_lst[1].ile3$w_code = 0; |
| 444 |
| 445 /* Translate the logical name. */ |
| 446 status = SYS$TRNLNM (0, /* Attr of the logical name. */ |
| 447 (void *) &tabdesc, /* Logical name table. */ |
| 448 (void *) &logdesc, /* Logical name. */ |
| 449 0, /* Access mode. */ |
| 450 item_lst); /* Item list. */ |
| 451 if (!(status & STS$M_SUCCESS)) |
| 452 LIB$SIGNAL (status); |
| 453 |
| 454 term_desc.dsc$w_length = len; |
| 455 |
| 456 /* Examine 4-byte header. Skip escape sequence. */ |
| 457 if (resstring[0] == 0x1B) |
| 458 { |
| 459 term_desc.dsc$w_length -= 4; |
| 460 term_desc.dsc$a_pointer += 4; |
| 461 } |
| 462 |
| 463 /* Assign a channel. */ |
| 464 status = sys$assign (&term_desc, /* Device name. */ |
| 465 &term_chan, /* I/O channel. */ |
| 466 0, /* Access mode. */ |
| 467 0); |
| 468 if (!(status & STS$M_SUCCESS)) |
| 469 LIB$SIGNAL (status); |
| 470 } |
| 471 |
| 472 /* Convert from native endianness to network endianness (and vice-versa). */ |
| 473 |
| 474 static unsigned int |
| 475 wordswap (unsigned int v) |
| 476 { |
| 477 return ((v & 0xff) << 8) | ((v >> 8) & 0xff); |
| 478 } |
| 479 |
| 480 /* Initialize the socket connection, and wait for a client. */ |
| 481 |
| 482 static void |
| 483 sock_init (void) |
| 484 { |
| 485 struct _iosb iosb; |
| 486 unsigned int status; |
| 487 |
| 488 /* Listen channel and characteristics. */ |
| 489 unsigned short listen_channel; |
| 490 struct sockchar listen_sockchar; |
| 491 |
| 492 /* Client address. */ |
| 493 unsigned short cli_addrlen; |
| 494 struct sockaddr_in cli_addr; |
| 495 ILE3 cli_itemlst; |
| 496 |
| 497 /* Our address. */ |
| 498 struct sockaddr_in serv_addr; |
| 499 ILE2 serv_itemlst; |
| 500 |
| 501 /* Reuseaddr option value (on). */ |
| 502 int optval = 1; |
| 503 ILE2 sockopt_itemlst; |
| 504 ILE2 reuseaddr_itemlst; |
| 505 |
| 506 /* TCP/IP network pseudodevice. */ |
| 507 static const $DESCRIPTOR (inet_device, "TCPIP$DEVICE:"); |
| 508 |
| 509 /* Initialize socket characteristics. */ |
| 510 listen_sockchar.prot = TCPIP$C_TCP; |
| 511 listen_sockchar.type = TCPIP$C_STREAM; |
| 512 listen_sockchar.af = TCPIP$C_AF_INET; |
| 513 |
| 514 /* Assign I/O channels to network device. */ |
| 515 status = sys$assign ((void *) &inet_device, &listen_channel, 0, 0); |
| 516 if (status & STS$M_SUCCESS) |
| 517 status = sys$assign ((void *) &inet_device, &conn_channel, 0, 0); |
| 518 if (!(status & STS$M_SUCCESS)) |
| 519 { |
| 520 term_puts ("Failed to assign I/O channel(s)\n"); |
| 521 LIB$SIGNAL (status); |
| 522 } |
| 523 |
| 524 /* Create a listen socket. */ |
| 525 status = sys$qiow (EFN$C_ENF, /* Event flag. */ |
| 526 listen_channel, /* I/O channel. */ |
| 527 IO$_SETMODE, /* I/O function code. */ |
| 528 &iosb, /* I/O status block. */ |
| 529 0, /* Ast service routine. */ |
| 530 0, /* Ast parameter. */ |
| 531 &listen_sockchar, /* P1 - socket characteristics. */ |
| 532 0, 0, 0, 0, 0); |
| 533 if (status & STS$M_SUCCESS) |
| 534 status = iosb.iosb$w_status; |
| 535 if (!(status & STS$M_SUCCESS)) |
| 536 { |
| 537 term_puts ("Failed to create socket\n"); |
| 538 LIB$SIGNAL (status); |
| 539 } |
| 540 |
| 541 /* Set reuse address option. */ |
| 542 /* Initialize reuseaddr's item-list element. */ |
| 543 reuseaddr_itemlst.ile2$w_length = sizeof (optval); |
| 544 reuseaddr_itemlst.ile2$w_code = TCPIP$C_REUSEADDR; |
| 545 reuseaddr_itemlst.ile2$ps_bufaddr = &optval; |
| 546 |
| 547 /* Initialize setsockopt's item-list descriptor. */ |
| 548 sockopt_itemlst.ile2$w_length = sizeof (reuseaddr_itemlst); |
| 549 sockopt_itemlst.ile2$w_code = TCPIP$C_SOCKOPT; |
| 550 sockopt_itemlst.ile2$ps_bufaddr = &reuseaddr_itemlst; |
| 551 |
| 552 status = sys$qiow (EFN$C_ENF, /* Event flag. */ |
| 553 listen_channel, /* I/O channel. */ |
| 554 IO$_SETMODE, /* I/O function code. */ |
| 555 &iosb, /* I/O status block. */ |
| 556 0, /* Ast service routine. */ |
| 557 0, /* Ast parameter. */ |
| 558 0, /* P1. */ |
| 559 0, /* P2. */ |
| 560 0, /* P3. */ |
| 561 0, /* P4. */ |
| 562 (__int64) &sockopt_itemlst, /* P5 - socket options. */ |
| 563 0); |
| 564 if (status & STS$M_SUCCESS) |
| 565 status = iosb.iosb$w_status; |
| 566 if (!(status & STS$M_SUCCESS)) |
| 567 { |
| 568 term_puts ("Failed to set socket option\n"); |
| 569 LIB$SIGNAL (status); |
| 570 } |
| 571 |
| 572 /* Bind server's ip address and port number to listen socket. */ |
| 573 /* Initialize server's socket address structure. */ |
| 574 ots$fill (&serv_addr, sizeof (serv_addr), 0); |
| 575 serv_addr.sin_family = TCPIP$C_AF_INET; |
| 576 serv_addr.sin_port = wordswap (serv_port); |
| 577 serv_addr.sin_addr.s_addr = TCPIP$C_INADDR_ANY; |
| 578 |
| 579 /* Initialize server's item-list descriptor. */ |
| 580 serv_itemlst.ile2$w_length = sizeof (serv_addr); |
| 581 serv_itemlst.ile2$w_code = TCPIP$C_SOCK_NAME; |
| 582 serv_itemlst.ile2$ps_bufaddr = &serv_addr; |
| 583 |
| 584 status = sys$qiow (EFN$C_ENF, /* Event flag. */ |
| 585 listen_channel, /* I/O channel. */ |
| 586 IO$_SETMODE, /* I/O function code. */ |
| 587 &iosb, /* I/O status block. */ |
| 588 0, /* Ast service routine. */ |
| 589 0, /* Ast parameter. */ |
| 590 0, /* P1. */ |
| 591 0, /* P2. */ |
| 592 (__int64) &serv_itemlst, /* P3 - local socket name. */ |
| 593 0, 0, 0); |
| 594 if (status & STS$M_SUCCESS) |
| 595 status = iosb.iosb$w_status; |
| 596 if (!(status & STS$M_SUCCESS)) |
| 597 { |
| 598 term_puts ("Failed to bind socket\n"); |
| 599 LIB$SIGNAL (status); |
| 600 } |
| 601 |
| 602 /* Set socket as a listen socket. */ |
| 603 status = sys$qiow (EFN$C_ENF, /* Event flag. */ |
| 604 listen_channel, /* I/O channel. */ |
| 605 IO$_SETMODE, /* I/O function code. */ |
| 606 &iosb, /* I/O status block. */ |
| 607 0, /* Ast service routine. */ |
| 608 0, /* Ast parameter. */ |
| 609 0, /* P1. */ |
| 610 0, /* P2. */ |
| 611 0, /* P3. */ |
| 612 1, /* P4 - connection backlog. */ |
| 613 0, 0); |
| 614 if (status & STS$M_SUCCESS) |
| 615 status = iosb.iosb$w_status; |
| 616 if (!(status & STS$M_SUCCESS)) |
| 617 { |
| 618 term_puts ("Failed to set socket passive\n"); |
| 619 LIB$SIGNAL (status); |
| 620 } |
| 621 |
| 622 /* Accept connection from a client. */ |
| 623 TERM_FAO ("Waiting for a client connection on port: !ZW!/", |
| 624 wordswap (serv_addr.sin_port)); |
| 625 |
| 626 status = sys$qiow (EFN$C_ENF, /* Event flag. */ |
| 627 listen_channel, /* I/O channel. */ |
| 628 IO$_ACCESS|IO$M_ACCEPT, /* I/O function code. */ |
| 629 &iosb, /* I/O status block. */ |
| 630 0, /* Ast service routine. */ |
| 631 0, /* Ast parameter. */ |
| 632 0, /* P1. */ |
| 633 0, /* P2. */ |
| 634 0, /* P3. */ |
| 635 (__int64) &conn_channel, /* P4 - I/O channel for conn. */ |
| 636 0, 0); |
| 637 |
| 638 if (status & STS$M_SUCCESS) |
| 639 status = iosb.iosb$w_status; |
| 640 if (!(status & STS$M_SUCCESS)) |
| 641 { |
| 642 term_puts ("Failed to accept client connection\n"); |
| 643 LIB$SIGNAL (status); |
| 644 } |
| 645 |
| 646 /* Log client connection request. */ |
| 647 cli_itemlst.ile3$w_length = sizeof (cli_addr); |
| 648 cli_itemlst.ile3$w_code = TCPIP$C_SOCK_NAME; |
| 649 cli_itemlst.ile3$ps_bufaddr = &cli_addr; |
| 650 cli_itemlst.ile3$ps_retlen_addr = &cli_addrlen; |
| 651 ots$fill (&cli_addr, sizeof(cli_addr), 0); |
| 652 status = sys$qiow (EFN$C_ENF, /* Event flag. */ |
| 653 conn_channel, /* I/O channel. */ |
| 654 IO$_SENSEMODE, /* I/O function code. */ |
| 655 &iosb, /* I/O status block. */ |
| 656 0, /* Ast service routine. */ |
| 657 0, /* Ast parameter. */ |
| 658 0, /* P1. */ |
| 659 0, /* P2. */ |
| 660 0, /* P3. */ |
| 661 (__int64) &cli_itemlst, /* P4 - peer socket name. */ |
| 662 0, 0); |
| 663 if (status & STS$M_SUCCESS) |
| 664 status = iosb.iosb$w_status; |
| 665 if (!(status & STS$M_SUCCESS)) |
| 666 { |
| 667 term_puts ("Failed to get client name\n"); |
| 668 LIB$SIGNAL (status); |
| 669 } |
| 670 |
| 671 TERM_FAO ("Accepted connection from host: !UB.!UB,!UB.!UB, port: !UW!/", |
| 672 (cli_addr.sin_addr.s_addr >> 0) & 0xff, |
| 673 (cli_addr.sin_addr.s_addr >> 8) & 0xff, |
| 674 (cli_addr.sin_addr.s_addr >> 16) & 0xff, |
| 675 (cli_addr.sin_addr.s_addr >> 24) & 0xff, |
| 676 wordswap (cli_addr.sin_port)); |
| 677 } |
| 678 |
| 679 /* Close the socket. */ |
| 680 |
| 681 static void |
| 682 sock_close (void) |
| 683 { |
| 684 struct _iosb iosb; |
| 685 unsigned int status; |
| 686 |
| 687 /* Close socket. */ |
| 688 status = sys$qiow (EFN$C_ENF, /* Event flag. */ |
| 689 conn_channel, /* I/O channel. */ |
| 690 IO$_DEACCESS, /* I/O function code. */ |
| 691 &iosb, /* I/O status block. */ |
| 692 0, /* Ast service routine. */ |
| 693 0, /* Ast parameter. */ |
| 694 0, 0, 0, 0, 0, 0); |
| 695 |
| 696 if (status & STS$M_SUCCESS) |
| 697 status = iosb.iosb$w_status; |
| 698 if (!(status & STS$M_SUCCESS)) |
| 699 { |
| 700 term_puts ("Failed to close socket\n"); |
| 701 LIB$SIGNAL (status); |
| 702 } |
| 703 |
| 704 /* Deassign I/O channel to network device. */ |
| 705 status = sys$dassgn (conn_channel); |
| 706 |
| 707 if (!(status & STS$M_SUCCESS)) |
| 708 { |
| 709 term_puts ("Failed to deassign I/O channel\n"); |
| 710 LIB$SIGNAL (status); |
| 711 } |
| 712 } |
| 713 |
| 714 /* Mark a page as R/W. Return old rights. */ |
| 715 |
| 716 static unsigned int |
| 717 page_set_rw (unsigned __int64 startva, unsigned __int64 len, |
| 718 unsigned int *oldprot) |
| 719 { |
| 720 unsigned int status; |
| 721 unsigned __int64 retva; |
| 722 unsigned __int64 retlen; |
| 723 |
| 724 status = SYS$SETPRT_64 ((void *)startva, len, PSL$C_USER, PRT$C_UW, |
| 725 (void *)&retva, &retlen, oldprot); |
| 726 return status; |
| 727 } |
| 728 |
| 729 /* Restore page rights. */ |
| 730 |
| 731 static void |
| 732 page_restore_rw (unsigned __int64 startva, unsigned __int64 len, |
| 733 unsigned int prot) |
| 734 { |
| 735 unsigned int status; |
| 736 unsigned __int64 retva; |
| 737 unsigned __int64 retlen; |
| 738 unsigned int oldprot; |
| 739 |
| 740 status = SYS$SETPRT_64 ((void *)startva, len, PSL$C_USER, prot, |
| 741 (void *)&retva, &retlen, &oldprot); |
| 742 if (!(status & STS$M_SUCCESS)) |
| 743 LIB$SIGNAL (status); |
| 744 } |
| 745 |
| 746 /* Get the TEB (thread environment block). */ |
| 747 |
| 748 static pthread_t |
| 749 get_teb (void) |
| 750 { |
| 751 return (pthread_t)__getReg (_IA64_REG_TP); |
| 752 } |
| 753 |
| 754 /* Enable thread scheduling if VAL is true. */ |
| 755 |
| 756 static unsigned int |
| 757 set_thread_scheduling (int val) |
| 758 { |
| 759 struct dbgext_control_block blk; |
| 760 unsigned int status; |
| 761 |
| 762 if (!dbgext_func) |
| 763 return 0; |
| 764 |
| 765 blk.dbgext$w_function_code = DBGEXT$K_STOP_ALL_OTHER_TASKS; |
| 766 blk.dbgext$w_facility_id = CMA$_FACILITY; |
| 767 blk.dbgext$l_stop_value = val; |
| 768 |
| 769 status = dbgext_func (&blk); |
| 770 if (!(status & STS$M_SUCCESS)) |
| 771 { |
| 772 TERM_FAO ("set_thread_scheduling error, val=!SL, status=!XL!/", |
| 773 val, blk.dbgext$l_status); |
| 774 lib$signal (status); |
| 775 } |
| 776 |
| 777 return blk.dbgext$l_stop_value; |
| 778 } |
| 779 |
| 780 /* Get next thead (after THR). Start with 0. */ |
| 781 |
| 782 static unsigned int |
| 783 thread_next (unsigned int thr) |
| 784 { |
| 785 struct dbgext_control_block blk; |
| 786 unsigned int status; |
| 787 |
| 788 if (!dbgext_func) |
| 789 return 0; |
| 790 |
| 791 blk.dbgext$w_function_code = DBGEXT$K_NEXT_TASK; |
| 792 blk.dbgext$w_facility_id = CMA$_FACILITY; |
| 793 blk.dbgext$l_ada_flags = 0; |
| 794 blk.dbgext$l_task_value = thr; |
| 795 |
| 796 status = dbgext_func (&blk); |
| 797 if (!(status & STS$M_SUCCESS)) |
| 798 lib$signal (status); |
| 799 |
| 800 return blk.dbgext$l_task_value; |
| 801 } |
| 802 |
| 803 /* Pthread Debug callbacks. */ |
| 804 |
| 805 static int |
| 806 read_callback (pthreadDebugClient_t context, |
| 807 pthreadDebugTargetAddr_t addr, |
| 808 pthreadDebugAddr_t buf, |
| 809 size_t size) |
| 810 { |
| 811 if (trace_pthreaddbg) |
| 812 TERM_FAO ("read_callback (!XH, !XH, !SL)!/", addr, buf, size); |
| 813 ots$move (buf, size, addr); |
| 814 return 0; |
| 815 } |
| 816 |
| 817 static int |
| 818 write_callback (pthreadDebugClient_t context, |
| 819 pthreadDebugTargetAddr_t addr, |
| 820 pthreadDebugLongConstAddr_t buf, |
| 821 size_t size) |
| 822 { |
| 823 if (trace_pthreaddbg) |
| 824 TERM_FAO ("write_callback (!XH, !XH, !SL)!/", addr, buf, size); |
| 825 ots$move (addr, size, buf); |
| 826 return 0; |
| 827 } |
| 828 |
| 829 static int |
| 830 suspend_callback (pthreadDebugClient_t context) |
| 831 { |
| 832 /* Always suspended. */ |
| 833 return 0; |
| 834 } |
| 835 |
| 836 static int |
| 837 resume_callback (pthreadDebugClient_t context) |
| 838 { |
| 839 /* So no need to resume. */ |
| 840 return 0; |
| 841 } |
| 842 |
| 843 static int |
| 844 kthdinfo_callback (pthreadDebugClient_t context, |
| 845 pthreadDebugKId_t kid, |
| 846 pthreadDebugKThreadInfo_p thread_info) |
| 847 { |
| 848 if (trace_pthreaddbg) |
| 849 term_puts ("kthinfo_callback"); |
| 850 return ENOSYS; |
| 851 } |
| 852 |
| 853 static int |
| 854 hold_callback (pthreadDebugClient_t context, |
| 855 pthreadDebugKId_t kid) |
| 856 { |
| 857 if (trace_pthreaddbg) |
| 858 term_puts ("hold_callback"); |
| 859 return ENOSYS; |
| 860 } |
| 861 |
| 862 static int |
| 863 unhold_callback (pthreadDebugClient_t context, |
| 864 pthreadDebugKId_t kid) |
| 865 { |
| 866 if (trace_pthreaddbg) |
| 867 term_puts ("unhold_callback"); |
| 868 return ENOSYS; |
| 869 } |
| 870 |
| 871 static int |
| 872 getfreg_callback (pthreadDebugClient_t context, |
| 873 pthreadDebugFregs_t *reg, |
| 874 pthreadDebugKId_t kid) |
| 875 { |
| 876 if (trace_pthreaddbg) |
| 877 term_puts ("getfreg_callback"); |
| 878 return ENOSYS; |
| 879 } |
| 880 |
| 881 static int |
| 882 setfreg_callback (pthreadDebugClient_t context, |
| 883 const pthreadDebugFregs_t *reg, |
| 884 pthreadDebugKId_t kid) |
| 885 { |
| 886 if (trace_pthreaddbg) |
| 887 term_puts ("setfreg_callback"); |
| 888 return ENOSYS; |
| 889 } |
| 890 |
| 891 static int |
| 892 getreg_callback (pthreadDebugClient_t context, |
| 893 pthreadDebugRegs_t *reg, |
| 894 pthreadDebugKId_t kid) |
| 895 { |
| 896 if (trace_pthreaddbg) |
| 897 term_puts ("getreg_callback"); |
| 898 return ENOSYS; |
| 899 } |
| 900 |
| 901 static int |
| 902 setreg_callback (pthreadDebugClient_t context, |
| 903 const pthreadDebugRegs_t *reg, |
| 904 pthreadDebugKId_t kid) |
| 905 { |
| 906 if (trace_pthreaddbg) |
| 907 term_puts ("setreg_callback"); |
| 908 return ENOSYS; |
| 909 } |
| 910 |
| 911 static int |
| 912 output_callback (pthreadDebugClient_t context, |
| 913 pthreadDebugConstString_t line) |
| 914 { |
| 915 term_puts (line); |
| 916 term_putnl (); |
| 917 return 0; |
| 918 } |
| 919 |
| 920 static int |
| 921 error_callback (pthreadDebugClient_t context, |
| 922 pthreadDebugConstString_t line) |
| 923 { |
| 924 term_puts (line); |
| 925 term_putnl (); |
| 926 return 0; |
| 927 } |
| 928 |
| 929 static pthreadDebugAddr_t |
| 930 malloc_callback (pthreadDebugClient_t caller_context, size_t size) |
| 931 { |
| 932 unsigned int status; |
| 933 unsigned int res; |
| 934 int len; |
| 935 |
| 936 len = size + 16; |
| 937 status = lib$get_vm (&len, &res, 0); |
| 938 if (!(status & STS$M_SUCCESS)) |
| 939 LIB$SIGNAL (status); |
| 940 if (trace_pthreaddbg) |
| 941 TERM_FAO ("malloc_callback (!UL) -> !XA!/", size, res); |
| 942 *(unsigned int *)res = len; |
| 943 return (char *)res + 16; |
| 944 } |
| 945 |
| 946 static void |
| 947 free_callback (pthreadDebugClient_t caller_context, pthreadDebugAddr_t address) |
| 948 { |
| 949 unsigned int status; |
| 950 unsigned int res; |
| 951 int len; |
| 952 |
| 953 res = (unsigned int)address - 16; |
| 954 len = *(unsigned int *)res; |
| 955 if (trace_pthreaddbg) |
| 956 TERM_FAO ("free_callback (!XA)!/", address); |
| 957 status = lib$free_vm (&len, &res, 0); |
| 958 if (!(status & STS$M_SUCCESS)) |
| 959 LIB$SIGNAL (status); |
| 960 } |
| 961 |
| 962 static int |
| 963 speckthd_callback (pthreadDebugClient_t caller_context, |
| 964 pthreadDebugSpecialType_t type, |
| 965 pthreadDebugKId_t *kernel_tid) |
| 966 { |
| 967 return ENOTSUP; |
| 968 } |
| 969 |
| 970 static pthreadDebugCallbacks_t pthread_debug_callbacks = { |
| 971 PTHREAD_DEBUG_VERSION, |
| 972 read_callback, |
| 973 write_callback, |
| 974 suspend_callback, |
| 975 resume_callback, |
| 976 kthdinfo_callback, |
| 977 hold_callback, |
| 978 unhold_callback, |
| 979 getfreg_callback, |
| 980 setfreg_callback, |
| 981 getreg_callback, |
| 982 setreg_callback, |
| 983 output_callback, |
| 984 error_callback, |
| 985 malloc_callback, |
| 986 free_callback, |
| 987 speckthd_callback |
| 988 }; |
| 989 |
| 990 /* Name of the pthread shared library. */ |
| 991 static const $DESCRIPTOR (pthread_rtl_desc, "PTHREAD$RTL"); |
| 992 |
| 993 /* List of symbols to extract from pthread debug library. */ |
| 994 struct pthread_debug_entry |
| 995 { |
| 996 const unsigned int namelen; |
| 997 const __char_ptr32 name; |
| 998 __void_ptr32 func; |
| 999 }; |
| 1000 |
| 1001 #define DEBUG_ENTRY(str) { sizeof(str) - 1, str, 0 } |
| 1002 |
| 1003 static struct pthread_debug_entry pthread_debug_entries[] = { |
| 1004 DEBUG_ENTRY("pthreadDebugContextInit"), |
| 1005 DEBUG_ENTRY("pthreadDebugThdSeqInit"), |
| 1006 DEBUG_ENTRY("pthreadDebugThdSeqNext"), |
| 1007 DEBUG_ENTRY("pthreadDebugThdSeqDestroy"), |
| 1008 DEBUG_ENTRY("pthreadDebugThdGetInfo"), |
| 1009 DEBUG_ENTRY("pthreadDebugThdGetInfoAddr"), |
| 1010 DEBUG_ENTRY("pthreadDebugThdGetReg"), |
| 1011 DEBUG_ENTRY("pthreadDebugCmd") |
| 1012 }; |
| 1013 |
| 1014 /* Pthread debug context. */ |
| 1015 static pthreadDebugContext_t debug_context; |
| 1016 |
| 1017 /* Wrapper around pthread debug entry points. */ |
| 1018 |
| 1019 static int |
| 1020 pthread_debug_thd_seq_init (pthreadDebugId_t *id) |
| 1021 { |
| 1022 return ((int (*)())pthread_debug_entries[1].func) |
| 1023 (debug_context, id); |
| 1024 } |
| 1025 |
| 1026 static int |
| 1027 pthread_debug_thd_seq_next (pthreadDebugId_t *id) |
| 1028 { |
| 1029 return ((int (*)())pthread_debug_entries[2].func) |
| 1030 (debug_context, id); |
| 1031 } |
| 1032 |
| 1033 static int |
| 1034 pthread_debug_thd_seq_destroy (void) |
| 1035 { |
| 1036 return ((int (*)())pthread_debug_entries[3].func) |
| 1037 (debug_context); |
| 1038 } |
| 1039 |
| 1040 static int |
| 1041 pthread_debug_thd_get_info (pthreadDebugId_t id, |
| 1042 pthreadDebugThreadInfo_t *info) |
| 1043 { |
| 1044 return ((int (*)())pthread_debug_entries[4].func) |
| 1045 (debug_context, id, info); |
| 1046 } |
| 1047 |
| 1048 static int |
| 1049 pthread_debug_thd_get_info_addr (pthread_t thr, |
| 1050 pthreadDebugThreadInfo_t *info) |
| 1051 { |
| 1052 return ((int (*)())pthread_debug_entries[5].func) |
| 1053 (debug_context, thr, info); |
| 1054 } |
| 1055 |
| 1056 static int |
| 1057 pthread_debug_thd_get_reg (pthreadDebugId_t thr, |
| 1058 pthreadDebugRegs_t *regs) |
| 1059 { |
| 1060 return ((int (*)())pthread_debug_entries[6].func) |
| 1061 (debug_context, thr, regs); |
| 1062 } |
| 1063 |
| 1064 static int |
| 1065 stub_pthread_debug_cmd (const char *cmd) |
| 1066 { |
| 1067 return ((int (*)())pthread_debug_entries[7].func) |
| 1068 (debug_context, cmd); |
| 1069 } |
| 1070 |
| 1071 /* Show all the threads. */ |
| 1072 |
| 1073 static void |
| 1074 threads_show (void) |
| 1075 { |
| 1076 pthreadDebugId_t id; |
| 1077 pthreadDebugThreadInfo_t info; |
| 1078 int res; |
| 1079 |
| 1080 res = pthread_debug_thd_seq_init (&id); |
| 1081 if (res != 0) |
| 1082 { |
| 1083 TERM_FAO ("seq init failed, res=!SL!/", res); |
| 1084 return; |
| 1085 } |
| 1086 while (1) |
| 1087 { |
| 1088 if (pthread_debug_thd_get_info (id, &info) != 0) |
| 1089 { |
| 1090 TERM_FAO ("thd_get_info !SL failed!/", id); |
| 1091 break; |
| 1092 } |
| 1093 if (pthread_debug_thd_seq_next (&id) != 0) |
| 1094 break; |
| 1095 } |
| 1096 pthread_debug_thd_seq_destroy (); |
| 1097 } |
| 1098 |
| 1099 /* Initialize pthread support. */ |
| 1100 |
| 1101 static void |
| 1102 threads_init (void) |
| 1103 { |
| 1104 static const $DESCRIPTOR (dbgext_desc, "PTHREAD$DBGEXT"); |
| 1105 static const $DESCRIPTOR (pthread_debug_desc, "PTHREAD$DBGSHR"); |
| 1106 static const $DESCRIPTOR (dbgsymtable_desc, "PTHREAD_DBG_SYMTABLE"); |
| 1107 int pthread_dbgext; |
| 1108 int status; |
| 1109 void *dbg_symtable; |
| 1110 int i; |
| 1111 void *caller_context = 0; |
| 1112 |
| 1113 status = lib$find_image_symbol |
| 1114 ((void *) &pthread_rtl_desc, (void *) &dbgext_desc, |
| 1115 (int *) &dbgext_func); |
| 1116 if (!(status & STS$M_SUCCESS)) |
| 1117 LIB$SIGNAL (status); |
| 1118 |
| 1119 status = lib$find_image_symbol |
| 1120 ((void *) &pthread_rtl_desc, (void *) &dbgsymtable_desc, |
| 1121 (int *) &dbg_symtable); |
| 1122 if (!(status & STS$M_SUCCESS)) |
| 1123 LIB$SIGNAL (status); |
| 1124 |
| 1125 /* Find entry points in pthread_debug. */ |
| 1126 for (i = 0; |
| 1127 i < sizeof (pthread_debug_entries) / sizeof (pthread_debug_entries[0]); |
| 1128 i++) |
| 1129 { |
| 1130 struct dsc$descriptor_s sym = |
| 1131 { pthread_debug_entries[i].namelen, |
| 1132 DSC$K_DTYPE_T, DSC$K_CLASS_S, |
| 1133 pthread_debug_entries[i].name }; |
| 1134 status = lib$find_image_symbol |
| 1135 ((void *) &pthread_debug_desc, (void *) &sym, |
| 1136 (int *) &pthread_debug_entries[i].func); |
| 1137 if (!(status & STS$M_SUCCESS)) |
| 1138 lib$signal (status); |
| 1139 } |
| 1140 |
| 1141 if (trace_pthreaddbg) |
| 1142 TERM_FAO ("debug symtable: !XH!/", dbg_symtable); |
| 1143 status = ((int (*)()) pthread_debug_entries[0].func) |
| 1144 (&caller_context, &pthread_debug_callbacks, dbg_symtable, &debug_context); |
| 1145 if (status != 0) |
| 1146 TERM_FAO ("cannot initialize pthread_debug: !UL!/", status); |
| 1147 TERM_FAO ("pthread debug done!/", 0); |
| 1148 } |
| 1149 |
| 1150 /* Convert an hexadecimal character to a nibble. Return -1 in case of |
| 1151 error. */ |
| 1152 |
| 1153 static int |
| 1154 hex2nibble (unsigned char h) |
| 1155 { |
| 1156 if (h >= '0' && h <= '9') |
| 1157 return h - '0'; |
| 1158 if (h >= 'A' && h <= 'F') |
| 1159 return h - 'A' + 10; |
| 1160 if (h >= 'a' && h <= 'f') |
| 1161 return h - 'a' + 10; |
| 1162 return -1; |
| 1163 } |
| 1164 |
| 1165 /* Convert an hexadecimal 2 character string to a byte. Return -1 in case |
| 1166 of error. */ |
| 1167 |
| 1168 static int |
| 1169 hex2byte (const unsigned char *p) |
| 1170 { |
| 1171 int h, l; |
| 1172 |
| 1173 h = hex2nibble (p[0]); |
| 1174 l = hex2nibble (p[1]); |
| 1175 if (h == -1 || l == -1) |
| 1176 return -1; |
| 1177 return (h << 4) | l; |
| 1178 } |
| 1179 |
| 1180 /* Convert a byte V to a 2 character strings P. */ |
| 1181 |
| 1182 static void |
| 1183 byte2hex (unsigned char *p, unsigned char v) |
| 1184 { |
| 1185 p[0] = hex[v >> 4]; |
| 1186 p[1] = hex[v & 0xf]; |
| 1187 } |
| 1188 |
| 1189 /* Convert a quadword V to a 16 character strings P. */ |
| 1190 |
| 1191 static void |
| 1192 quad2hex (unsigned char *p, unsigned __int64 v) |
| 1193 { |
| 1194 int i; |
| 1195 for (i = 0; i < 16; i++) |
| 1196 { |
| 1197 p[i] = hex[v >> 60]; |
| 1198 v <<= 4; |
| 1199 } |
| 1200 } |
| 1201 |
| 1202 static void |
| 1203 long2pkt (unsigned int v) |
| 1204 { |
| 1205 int i; |
| 1206 |
| 1207 for (i = 0; i < 8; i++) |
| 1208 { |
| 1209 gdb_buf[gdb_blen + i] = hex[(v >> 28) & 0x0f]; |
| 1210 v <<= 4; |
| 1211 } |
| 1212 gdb_blen += 8; |
| 1213 } |
| 1214 |
| 1215 /* Generate an error packet. */ |
| 1216 |
| 1217 static void |
| 1218 packet_error (unsigned int err) |
| 1219 { |
| 1220 gdb_buf[1] = 'E'; |
| 1221 byte2hex (gdb_buf + 2, err); |
| 1222 gdb_blen = 4; |
| 1223 } |
| 1224 |
| 1225 /* Generate an OK packet. */ |
| 1226 |
| 1227 static void |
| 1228 packet_ok (void) |
| 1229 { |
| 1230 gdb_buf[1] = 'O'; |
| 1231 gdb_buf[2] = 'K'; |
| 1232 gdb_blen = 3; |
| 1233 } |
| 1234 |
| 1235 /* Append a register to the packet. */ |
| 1236 |
| 1237 static void |
| 1238 ireg2pkt (const unsigned char *p) |
| 1239 { |
| 1240 int i; |
| 1241 |
| 1242 for (i = 0; i < 8; i++) |
| 1243 { |
| 1244 byte2hex (gdb_buf + gdb_blen, p[i]); |
| 1245 gdb_blen += 2; |
| 1246 } |
| 1247 } |
| 1248 |
| 1249 /* Append a C string (ASCIZ) to the packet. */ |
| 1250 |
| 1251 static void |
| 1252 str2pkt (const char *str) |
| 1253 { |
| 1254 while (*str) |
| 1255 gdb_buf[gdb_blen++] = *str++; |
| 1256 } |
| 1257 |
| 1258 /* Extract a number fro the packet. */ |
| 1259 |
| 1260 static unsigned __int64 |
| 1261 pkt2val (const unsigned char *pkt, unsigned int *pos) |
| 1262 { |
| 1263 unsigned __int64 res = 0; |
| 1264 unsigned int i; |
| 1265 |
| 1266 while (1) |
| 1267 { |
| 1268 int r = hex2nibble (pkt[*pos]); |
| 1269 |
| 1270 if (r < 0) |
| 1271 return res; |
| 1272 res = (res << 4) | r; |
| 1273 (*pos)++; |
| 1274 } |
| 1275 } |
| 1276 |
| 1277 /* Append LEN bytes from B to the current gdb packet (encode in binary). */ |
| 1278 |
| 1279 static void |
| 1280 mem2bin (const unsigned char *b, unsigned int len) |
| 1281 { |
| 1282 unsigned int i; |
| 1283 for (i = 0; i < len; i++) |
| 1284 switch (b[i]) |
| 1285 { |
| 1286 case '#': |
| 1287 case '$': |
| 1288 case '}': |
| 1289 case '*': |
| 1290 case 0: |
| 1291 gdb_buf[gdb_blen++] = '}'; |
| 1292 gdb_buf[gdb_blen++] = b[i] ^ 0x20; |
| 1293 break; |
| 1294 default: |
| 1295 gdb_buf[gdb_blen++] = b[i]; |
| 1296 break; |
| 1297 } |
| 1298 } |
| 1299 |
| 1300 /* Append LEN bytes from B to the current gdb packet (encode in hex). */ |
| 1301 |
| 1302 static void |
| 1303 mem2hex (const unsigned char *b, unsigned int len) |
| 1304 { |
| 1305 unsigned int i; |
| 1306 for (i = 0; i < len; i++) |
| 1307 { |
| 1308 byte2hex (gdb_buf + gdb_blen, b[i]); |
| 1309 gdb_blen += 2; |
| 1310 } |
| 1311 } |
| 1312 |
| 1313 /* Handle the 'q' packet. */ |
| 1314 |
| 1315 static void |
| 1316 handle_q_packet (const unsigned char *pkt, unsigned int pktlen) |
| 1317 { |
| 1318 /* For qfThreadInfo and qsThreadInfo. */ |
| 1319 static unsigned int first_thread; |
| 1320 static unsigned int last_thread; |
| 1321 |
| 1322 static const char xfer_uib[] = "qXfer:uib:read:"; |
| 1323 #define XFER_UIB_LEN (sizeof (xfer_uib) - 1) |
| 1324 static const char qfthreadinfo[] = "qfThreadInfo"; |
| 1325 #define QFTHREADINFO_LEN (sizeof (qfthreadinfo) - 1) |
| 1326 static const char qsthreadinfo[] = "qsThreadInfo"; |
| 1327 #define QSTHREADINFO_LEN (sizeof (qsthreadinfo) - 1) |
| 1328 static const char qthreadextrainfo[] = "qThreadExtraInfo,"; |
| 1329 #define QTHREADEXTRAINFO_LEN (sizeof (qthreadextrainfo) - 1) |
| 1330 static const char qsupported[] = "qSupported:"; |
| 1331 #define QSUPPORTED_LEN (sizeof (qsupported) - 1) |
| 1332 |
| 1333 if (pktlen == 2 && pkt[1] == 'C') |
| 1334 { |
| 1335 /* Current thread. */ |
| 1336 gdb_buf[0] = '$'; |
| 1337 gdb_buf[1] = 'Q'; |
| 1338 gdb_buf[2] = 'C'; |
| 1339 gdb_blen = 3; |
| 1340 if (has_threads) |
| 1341 long2pkt ((unsigned long) get_teb ()); |
| 1342 return; |
| 1343 } |
| 1344 else if (pktlen > XFER_UIB_LEN |
| 1345 && ots$strcmp_eql (pkt, XFER_UIB_LEN, xfer_uib, XFER_UIB_LEN)) |
| 1346 { |
| 1347 /* Get unwind information block. */ |
| 1348 unsigned __int64 pc; |
| 1349 unsigned int pos = XFER_UIB_LEN; |
| 1350 unsigned int off; |
| 1351 unsigned int len; |
| 1352 union |
| 1353 { |
| 1354 unsigned char bytes[32]; |
| 1355 struct |
| 1356 { |
| 1357 unsigned __int64 code_start_va; |
| 1358 unsigned __int64 code_end_va; |
| 1359 unsigned __int64 uib_start_va; |
| 1360 unsigned __int64 gp_value; |
| 1361 } data; |
| 1362 } uei; |
| 1363 int res; |
| 1364 int i; |
| 1365 |
| 1366 packet_error (0); |
| 1367 |
| 1368 pc = pkt2val (pkt, &pos); |
| 1369 if (pkt[pos] != ':') |
| 1370 return; |
| 1371 pos++; |
| 1372 off = pkt2val (pkt, &pos); |
| 1373 if (pkt[pos] != ',' || off != 0) |
| 1374 return; |
| 1375 pos++; |
| 1376 len = pkt2val (pkt, &pos); |
| 1377 if (pkt[pos] != '#' || len != 0x20) |
| 1378 return; |
| 1379 |
| 1380 res = SYS$GET_UNWIND_ENTRY_INFO (pc, &uei.data, 0); |
| 1381 if (res == SS$_NODATA || res != SS$_NORMAL) |
| 1382 ots$fill (uei.bytes, sizeof (uei.bytes), 0); |
| 1383 |
| 1384 if (trace_unwind) |
| 1385 { |
| 1386 TERM_FAO ("Unwind request for !XH, status=!XL, uib=!XQ, GP=!XQ!/", |
| 1387 pc, res, uei.data.uib_start_va, uei.data.gp_value); |
| 1388 } |
| 1389 |
| 1390 gdb_buf[0] = '$'; |
| 1391 gdb_buf[1] = 'l'; |
| 1392 gdb_blen = 2; |
| 1393 mem2bin (uei.bytes, sizeof (uei.bytes)); |
| 1394 } |
| 1395 else if (pktlen == QFTHREADINFO_LEN |
| 1396 && ots$strcmp_eql (pkt, QFTHREADINFO_LEN, |
| 1397 qfthreadinfo, QFTHREADINFO_LEN)) |
| 1398 { |
| 1399 /* Get first thread(s). */ |
| 1400 gdb_buf[0] = '$'; |
| 1401 gdb_buf[1] = 'm'; |
| 1402 gdb_blen = 2; |
| 1403 |
| 1404 if (!has_threads) |
| 1405 { |
| 1406 gdb_buf[1] = 'l'; |
| 1407 return; |
| 1408 } |
| 1409 first_thread = thread_next (0); |
| 1410 last_thread = first_thread; |
| 1411 long2pkt (first_thread); |
| 1412 } |
| 1413 else if (pktlen == QSTHREADINFO_LEN |
| 1414 && ots$strcmp_eql (pkt, QSTHREADINFO_LEN, |
| 1415 qsthreadinfo, QSTHREADINFO_LEN)) |
| 1416 { |
| 1417 /* Get subsequent threads. */ |
| 1418 gdb_buf[0] = '$'; |
| 1419 gdb_buf[1] = 'm'; |
| 1420 gdb_blen = 2; |
| 1421 while (dbgext_func) |
| 1422 { |
| 1423 unsigned int res; |
| 1424 res = thread_next (last_thread); |
| 1425 if (res == first_thread) |
| 1426 break; |
| 1427 if (gdb_blen > 2) |
| 1428 gdb_buf[gdb_blen++] = ','; |
| 1429 long2pkt (res); |
| 1430 last_thread = res; |
| 1431 if (gdb_blen > sizeof (gdb_buf) - 16) |
| 1432 break; |
| 1433 } |
| 1434 |
| 1435 if (gdb_blen == 2) |
| 1436 gdb_buf[1] = 'l'; |
| 1437 } |
| 1438 else if (pktlen > QTHREADEXTRAINFO_LEN |
| 1439 && ots$strcmp_eql (pkt, QTHREADEXTRAINFO_LEN, |
| 1440 qthreadextrainfo, QTHREADEXTRAINFO_LEN)) |
| 1441 { |
| 1442 /* Get extra info about a thread. */ |
| 1443 pthread_t thr; |
| 1444 unsigned int pos = QTHREADEXTRAINFO_LEN; |
| 1445 pthreadDebugThreadInfo_t info; |
| 1446 int res; |
| 1447 |
| 1448 packet_error (0); |
| 1449 if (!has_threads) |
| 1450 return; |
| 1451 |
| 1452 thr = (pthread_t) pkt2val (pkt, &pos); |
| 1453 if (pkt[pos] != '#') |
| 1454 return; |
| 1455 res = pthread_debug_thd_get_info_addr (thr, &info); |
| 1456 if (res != 0) |
| 1457 { |
| 1458 TERM_FAO ("qThreadExtraInfo (!XH) failed: !SL!/", thr, res); |
| 1459 return; |
| 1460 } |
| 1461 gdb_buf[0] = '$'; |
| 1462 gdb_blen = 1; |
| 1463 mem2hex ((const unsigned char *)"VMS-thread", 11); |
| 1464 } |
| 1465 else if (pktlen > QSUPPORTED_LEN |
| 1466 && ots$strcmp_eql (pkt, QSUPPORTED_LEN, |
| 1467 qsupported, QSUPPORTED_LEN)) |
| 1468 { |
| 1469 /* Get supported features. */ |
| 1470 pthread_t thr; |
| 1471 unsigned int pos = QSUPPORTED_LEN; |
| 1472 pthreadDebugThreadInfo_t info; |
| 1473 int res; |
| 1474 |
| 1475 /* Ignore gdb features. */ |
| 1476 gdb_buf[0] = '$'; |
| 1477 gdb_blen = 1; |
| 1478 |
| 1479 str2pkt ("qXfer:uib:read+"); |
| 1480 return; |
| 1481 } |
| 1482 else |
| 1483 { |
| 1484 if (trace_pkt) |
| 1485 { |
| 1486 term_puts ("unknown <: "); |
| 1487 term_write ((char *)pkt, pktlen); |
| 1488 term_putnl (); |
| 1489 } |
| 1490 return; |
| 1491 } |
| 1492 } |
| 1493 |
| 1494 /* Handle the 'v' packet. */ |
| 1495 |
| 1496 static int |
| 1497 handle_v_packet (const unsigned char *pkt, unsigned int pktlen) |
| 1498 { |
| 1499 static const char vcontq[] = "vCont?"; |
| 1500 #define VCONTQ_LEN (sizeof (vcontq) - 1) |
| 1501 |
| 1502 if (pktlen == VCONTQ_LEN |
| 1503 && ots$strcmp_eql (pkt, VCONTQ_LEN, vcontq, VCONTQ_LEN)) |
| 1504 { |
| 1505 gdb_buf[0] = '$'; |
| 1506 gdb_blen = 1; |
| 1507 |
| 1508 str2pkt ("vCont;c;s"); |
| 1509 return 0; |
| 1510 } |
| 1511 else |
| 1512 { |
| 1513 if (trace_pkt) |
| 1514 { |
| 1515 term_puts ("unknown <: "); |
| 1516 term_write ((char *)pkt, pktlen); |
| 1517 term_putnl (); |
| 1518 } |
| 1519 return 0; |
| 1520 } |
| 1521 } |
| 1522 |
| 1523 /* Get regs for the selected thread. */ |
| 1524 |
| 1525 static struct ia64_all_regs * |
| 1526 get_selected_regs (void) |
| 1527 { |
| 1528 pthreadDebugRegs_t regs; |
| 1529 int res; |
| 1530 |
| 1531 if (selected_thread == 0 || selected_thread == get_teb ()) |
| 1532 return &excp_regs; |
| 1533 |
| 1534 if (selected_thread == sel_regs_pthread) |
| 1535 return &sel_regs; |
| 1536 |
| 1537 /* Read registers. */ |
| 1538 res = pthread_debug_thd_get_reg (selected_id, ®s); |
| 1539 if (res != 0) |
| 1540 { |
| 1541 /* FIXME: return NULL ? */ |
| 1542 return &excp_regs; |
| 1543 } |
| 1544 sel_regs_pthread = selected_thread; |
| 1545 sel_regs.gr[1].v = regs.gp; |
| 1546 sel_regs.gr[4].v = regs.r4; |
| 1547 sel_regs.gr[5].v = regs.r5; |
| 1548 sel_regs.gr[6].v = regs.r6; |
| 1549 sel_regs.gr[7].v = regs.r7; |
| 1550 sel_regs.gr[12].v = regs.sp; |
| 1551 sel_regs.br[0].v = regs.rp; |
| 1552 sel_regs.br[1].v = regs.b1; |
| 1553 sel_regs.br[2].v = regs.b2; |
| 1554 sel_regs.br[3].v = regs.b3; |
| 1555 sel_regs.br[4].v = regs.b4; |
| 1556 sel_regs.br[5].v = regs.b5; |
| 1557 sel_regs.ip.v = regs.ip; |
| 1558 sel_regs.bsp.v = regs.bspstore; /* FIXME: it is correct ? */ |
| 1559 sel_regs.pfs.v = regs.pfs; |
| 1560 sel_regs.pr.v = regs.pr; |
| 1561 return &sel_regs; |
| 1562 } |
| 1563 |
| 1564 /* Create a status packet. */ |
| 1565 |
| 1566 static void |
| 1567 packet_status (void) |
| 1568 { |
| 1569 gdb_blen = 0; |
| 1570 if (has_threads) |
| 1571 { |
| 1572 str2pkt ("$T05thread:"); |
| 1573 long2pkt ((unsigned long) get_teb ()); |
| 1574 gdb_buf[gdb_blen++] = ';'; |
| 1575 } |
| 1576 else |
| 1577 str2pkt ("$S05"); |
| 1578 } |
| 1579 |
| 1580 /* Return 1 to continue. */ |
| 1581 |
| 1582 static int |
| 1583 handle_packet (unsigned char *pkt, unsigned int len) |
| 1584 { |
| 1585 unsigned int pos; |
| 1586 |
| 1587 /* By default, reply unsupported. */ |
| 1588 gdb_buf[0] = '$'; |
| 1589 gdb_blen = 1; |
| 1590 |
| 1591 pos = 1; |
| 1592 switch (pkt[0]) |
| 1593 { |
| 1594 case '?': |
| 1595 if (len == 1) |
| 1596 { |
| 1597 packet_status (); |
| 1598 return 0; |
| 1599 } |
| 1600 break; |
| 1601 case 'c': |
| 1602 if (len == 1) |
| 1603 { |
| 1604 /* Clear psr.ss. */ |
| 1605 excp_regs.psr.v &= ~(unsigned __int64)PSR$M_SS; |
| 1606 return 1; |
| 1607 } |
| 1608 else |
| 1609 packet_error (0); |
| 1610 break; |
| 1611 case 'g': |
| 1612 if (len == 1) |
| 1613 { |
| 1614 unsigned int i; |
| 1615 struct ia64_all_regs *regs = get_selected_regs (); |
| 1616 unsigned char *p = regs->gr[0].b; |
| 1617 |
| 1618 for (i = 0; i < 8 * 32; i++) |
| 1619 byte2hex (gdb_buf + 1 + 2 * i, p[i]); |
| 1620 gdb_blen += 2 * 8 * 32; |
| 1621 return 0; |
| 1622 } |
| 1623 break; |
| 1624 case 'H': |
| 1625 if (pkt[1] == 'g') |
| 1626 { |
| 1627 int res; |
| 1628 unsigned __int64 val; |
| 1629 pthreadDebugThreadInfo_t info; |
| 1630 |
| 1631 pos++; |
| 1632 val = pkt2val (pkt, &pos); |
| 1633 if (pos != len) |
| 1634 { |
| 1635 packet_error (0); |
| 1636 return 0; |
| 1637 } |
| 1638 if (val == 0) |
| 1639 { |
| 1640 /* Default one. */ |
| 1641 selected_thread = get_teb (); |
| 1642 selected_id = 0; |
| 1643 } |
| 1644 else if (!has_threads) |
| 1645 { |
| 1646 packet_error (0); |
| 1647 return 0; |
| 1648 } |
| 1649 else |
| 1650 { |
| 1651 res = pthread_debug_thd_get_info_addr ((pthread_t) val, &info); |
| 1652 if (res != 0) |
| 1653 { |
| 1654 TERM_FAO ("qThreadExtraInfo (!XH) failed: !SL!/", val, res); |
| 1655 packet_error (0); |
| 1656 return 0; |
| 1657 } |
| 1658 selected_thread = info.teb; |
| 1659 selected_id = info.sequence; |
| 1660 } |
| 1661 packet_ok (); |
| 1662 break; |
| 1663 } |
| 1664 else if (pkt[1] == 'c' |
| 1665 && ((pkt[2] == '-' && pkt[3] == '1' && len == 4) |
| 1666 || (pkt[2] == '0' && len == 3))) |
| 1667 { |
| 1668 /* Silently accept 'Hc0' and 'Hc-1'. */ |
| 1669 packet_ok (); |
| 1670 break; |
| 1671 } |
| 1672 else |
| 1673 { |
| 1674 packet_error (0); |
| 1675 return 0; |
| 1676 } |
| 1677 case 'k': |
| 1678 SYS$EXIT (SS$_NORMAL); |
| 1679 break; |
| 1680 case 'm': |
| 1681 { |
| 1682 unsigned __int64 addr; |
| 1683 unsigned __int64 paddr; |
| 1684 unsigned int l; |
| 1685 unsigned int i; |
| 1686 |
| 1687 addr = pkt2val (pkt, &pos); |
| 1688 if (pkt[pos] != ',') |
| 1689 { |
| 1690 packet_error (0); |
| 1691 return 0; |
| 1692 } |
| 1693 pos++; |
| 1694 l = pkt2val (pkt, &pos); |
| 1695 if (pkt[pos] != '#') |
| 1696 { |
| 1697 packet_error (0); |
| 1698 return 0; |
| 1699 } |
| 1700 |
| 1701 /* Check access. */ |
| 1702 i = l + (addr & VMS_PAGE_MASK); |
| 1703 paddr = addr & ~VMS_PAGE_MASK; |
| 1704 while (1) |
| 1705 { |
| 1706 if (__prober (paddr, 0) != 1) |
| 1707 { |
| 1708 packet_error (2); |
| 1709 return 0; |
| 1710 } |
| 1711 if (i < VMS_PAGE_SIZE) |
| 1712 break; |
| 1713 i -= VMS_PAGE_SIZE; |
| 1714 paddr += VMS_PAGE_SIZE; |
| 1715 } |
| 1716 |
| 1717 /* Transfer. */ |
| 1718 for (i = 0; i < l; i++) |
| 1719 byte2hex (gdb_buf + 1 + 2 * i, ((unsigned char *)addr)[i]); |
| 1720 gdb_blen += 2 * l; |
| 1721 } |
| 1722 break; |
| 1723 case 'M': |
| 1724 { |
| 1725 unsigned __int64 addr; |
| 1726 unsigned __int64 paddr; |
| 1727 unsigned int l; |
| 1728 unsigned int i; |
| 1729 unsigned int oldprot; |
| 1730 |
| 1731 addr = pkt2val (pkt, &pos); |
| 1732 if (pkt[pos] != ',') |
| 1733 { |
| 1734 packet_error (0); |
| 1735 return 0; |
| 1736 } |
| 1737 pos++; |
| 1738 l = pkt2val (pkt, &pos); |
| 1739 if (pkt[pos] != ':') |
| 1740 { |
| 1741 packet_error (0); |
| 1742 return 0; |
| 1743 } |
| 1744 pos++; |
| 1745 page_set_rw (addr, l, &oldprot); |
| 1746 |
| 1747 /* Check access. */ |
| 1748 i = l + (addr & VMS_PAGE_MASK); |
| 1749 paddr = addr & ~VMS_PAGE_MASK; |
| 1750 while (1) |
| 1751 { |
| 1752 if (__probew (paddr, 0) != 1) |
| 1753 { |
| 1754 page_restore_rw (addr, l, oldprot); |
| 1755 return 0; |
| 1756 } |
| 1757 if (i < VMS_PAGE_SIZE) |
| 1758 break; |
| 1759 i -= VMS_PAGE_SIZE; |
| 1760 paddr += VMS_PAGE_SIZE; |
| 1761 } |
| 1762 |
| 1763 /* Write. */ |
| 1764 for (i = 0; i < l; i++) |
| 1765 { |
| 1766 int v = hex2byte (pkt + pos); |
| 1767 pos += 2; |
| 1768 ((unsigned char *)addr)[i] = v; |
| 1769 } |
| 1770 |
| 1771 /* Sync caches. */ |
| 1772 for (i = 0; i < l; i += 15) |
| 1773 __fc (addr + i); |
| 1774 __fc (addr + l); |
| 1775 |
| 1776 page_restore_rw (addr, l, oldprot); |
| 1777 packet_ok (); |
| 1778 } |
| 1779 break; |
| 1780 case 'p': |
| 1781 { |
| 1782 unsigned int num = 0; |
| 1783 unsigned int i; |
| 1784 struct ia64_all_regs *regs = get_selected_regs (); |
| 1785 |
| 1786 num = pkt2val (pkt, &pos); |
| 1787 if (pos != len) |
| 1788 { |
| 1789 packet_error (0); |
| 1790 return 0; |
| 1791 } |
| 1792 |
| 1793 switch (num) |
| 1794 { |
| 1795 case IA64_IP_REGNUM: |
| 1796 ireg2pkt (regs->ip.b); |
| 1797 break; |
| 1798 case IA64_BR0_REGNUM: |
| 1799 ireg2pkt (regs->br[0].b); |
| 1800 break; |
| 1801 case IA64_PSR_REGNUM: |
| 1802 ireg2pkt (regs->psr.b); |
| 1803 break; |
| 1804 case IA64_BSP_REGNUM: |
| 1805 ireg2pkt (regs->bsp.b); |
| 1806 break; |
| 1807 case IA64_CFM_REGNUM: |
| 1808 ireg2pkt (regs->cfm.b); |
| 1809 break; |
| 1810 case IA64_PFS_REGNUM: |
| 1811 ireg2pkt (regs->pfs.b); |
| 1812 break; |
| 1813 case IA64_PR_REGNUM: |
| 1814 ireg2pkt (regs->pr.b); |
| 1815 break; |
| 1816 default: |
| 1817 TERM_FAO ("gdbserv: unhandled reg !UW!/", num); |
| 1818 packet_error (0); |
| 1819 return 0; |
| 1820 } |
| 1821 } |
| 1822 break; |
| 1823 case 'q': |
| 1824 handle_q_packet (pkt, len); |
| 1825 break; |
| 1826 case 's': |
| 1827 if (len == 1) |
| 1828 { |
| 1829 /* Set psr.ss. */ |
| 1830 excp_regs.psr.v |= (unsigned __int64)PSR$M_SS; |
| 1831 return 1; |
| 1832 } |
| 1833 else |
| 1834 packet_error (0); |
| 1835 break; |
| 1836 case 'T': |
| 1837 /* Thread status. */ |
| 1838 if (!has_threads) |
| 1839 { |
| 1840 packet_ok (); |
| 1841 break; |
| 1842 } |
| 1843 else |
| 1844 { |
| 1845 int res; |
| 1846 unsigned __int64 val; |
| 1847 unsigned int fthr, thr; |
| 1848 |
| 1849 val = pkt2val (pkt, &pos); |
| 1850 /* Default is error (but only after parsing is complete). */ |
| 1851 packet_error (0); |
| 1852 if (pos != len) |
| 1853 break; |
| 1854 |
| 1855 /* Follow the list. This makes a O(n2) algorithm, but we don't really |
| 1856 have the choice. Note that pthread_debug_thd_get_info_addr |
| 1857 doesn't look reliable. */ |
| 1858 fthr = thread_next (0); |
| 1859 thr = fthr; |
| 1860 do |
| 1861 { |
| 1862 if (val == thr) |
| 1863 { |
| 1864 packet_ok (); |
| 1865 break; |
| 1866 } |
| 1867 thr = thread_next (thr); |
| 1868 } |
| 1869 while (thr != fthr); |
| 1870 } |
| 1871 break; |
| 1872 case 'v': |
| 1873 return handle_v_packet (pkt, len); |
| 1874 break; |
| 1875 case 'V': |
| 1876 if (len > 3 && pkt[1] == 'M' && pkt[2] == 'S' && pkt[3] == ' ') |
| 1877 { |
| 1878 /* Temporary extension. */ |
| 1879 if (has_threads) |
| 1880 { |
| 1881 pkt[len] = 0; |
| 1882 stub_pthread_debug_cmd ((char *)pkt + 4); |
| 1883 packet_ok (); |
| 1884 } |
| 1885 else |
| 1886 packet_error (0); |
| 1887 } |
| 1888 break; |
| 1889 default: |
| 1890 if (trace_pkt) |
| 1891 { |
| 1892 term_puts ("unknown <: "); |
| 1893 term_write ((char *)pkt, len); |
| 1894 term_putnl (); |
| 1895 } |
| 1896 break; |
| 1897 } |
| 1898 return 0; |
| 1899 } |
| 1900 |
| 1901 /* Raw write to gdb. */ |
| 1902 |
| 1903 static void |
| 1904 sock_write (const unsigned char *buf, int len) |
| 1905 { |
| 1906 struct _iosb iosb; |
| 1907 unsigned int status; |
| 1908 |
| 1909 /* Write data to connection. */ |
| 1910 status = sys$qiow (EFN$C_ENF, /* Event flag. */ |
| 1911 conn_channel, /* I/O channel. */ |
| 1912 IO$_WRITEVBLK, /* I/O function code. */ |
| 1913 &iosb, /* I/O status block. */ |
| 1914 0, /* Ast service routine. */ |
| 1915 0, /* Ast parameter. */ |
| 1916 (char *)buf, /* P1 - buffer address. */ |
| 1917 len, /* P2 - buffer length. */ |
| 1918 0, 0, 0, 0); |
| 1919 if (status & STS$M_SUCCESS) |
| 1920 status = iosb.iosb$w_status; |
| 1921 if (!(status & STS$M_SUCCESS)) |
| 1922 { |
| 1923 term_puts ("Failed to write data to gdb\n"); |
| 1924 LIB$SIGNAL (status); |
| 1925 } |
| 1926 } |
| 1927 |
| 1928 /* Compute the cheksum and send the packet. */ |
| 1929 |
| 1930 static void |
| 1931 send_pkt (void) |
| 1932 { |
| 1933 unsigned char chksum = 0; |
| 1934 unsigned int i; |
| 1935 |
| 1936 for (i = 1; i < gdb_blen; i++) |
| 1937 chksum += gdb_buf[i]; |
| 1938 |
| 1939 gdb_buf[gdb_blen] = '#'; |
| 1940 byte2hex (gdb_buf + gdb_blen + 1, chksum); |
| 1941 |
| 1942 sock_write (gdb_buf, gdb_blen + 3); |
| 1943 |
| 1944 if (trace_pkt > 1) |
| 1945 { |
| 1946 term_puts (">: "); |
| 1947 term_write ((char *)gdb_buf, gdb_blen + 3); |
| 1948 term_putnl (); |
| 1949 } |
| 1950 } |
| 1951 |
| 1952 /* Read and handle one command. Return 1 is execution must resume. */ |
| 1953 |
| 1954 static int |
| 1955 one_command (void) |
| 1956 { |
| 1957 struct _iosb iosb; |
| 1958 unsigned int status; |
| 1959 unsigned int off; |
| 1960 unsigned int dollar_off = 0; |
| 1961 unsigned int sharp_off = 0; |
| 1962 unsigned int cmd_off; |
| 1963 unsigned int cmd_len; |
| 1964 |
| 1965 /* Wait for a packet. */ |
| 1966 while (1) |
| 1967 { |
| 1968 off = 0; |
| 1969 while (1) |
| 1970 { |
| 1971 /* Read data from connection. */ |
| 1972 status = sys$qiow (EFN$C_ENF, /* Event flag. */ |
| 1973 conn_channel, /* I/O channel. */ |
| 1974 IO$_READVBLK, /* I/O function code. */ |
| 1975 &iosb, /* I/O status block. */ |
| 1976 0, /* Ast service routine. */ |
| 1977 0, /* Ast parameter. */ |
| 1978 gdb_buf + off, /* P1 - buffer address. */ |
| 1979 sizeof (gdb_buf) - off, /* P2 - buffer leng. */ |
| 1980 0, 0, 0, 0); |
| 1981 if (status & STS$M_SUCCESS) |
| 1982 status = iosb.iosb$w_status; |
| 1983 if (!(status & STS$M_SUCCESS)) |
| 1984 { |
| 1985 term_puts ("Failed to read data from connection\n" ); |
| 1986 LIB$SIGNAL (status); |
| 1987 } |
| 1988 |
| 1989 #ifdef RAW_DUMP |
| 1990 term_puts ("{: "); |
| 1991 term_write ((char *)gdb_buf + off, iosb.iosb$w_bcnt); |
| 1992 term_putnl (); |
| 1993 #endif |
| 1994 |
| 1995 gdb_blen = off + iosb.iosb$w_bcnt; |
| 1996 |
| 1997 if (off == 0) |
| 1998 { |
| 1999 /* Search for '$'. */ |
| 2000 for (dollar_off = 0; dollar_off < gdb_blen; dollar_off++) |
| 2001 if (gdb_buf[dollar_off] == '$') |
| 2002 break; |
| 2003 if (dollar_off >= gdb_blen) |
| 2004 { |
| 2005 /* Not found, discard the data. */ |
| 2006 off = 0; |
| 2007 continue; |
| 2008 } |
| 2009 /* Search for '#'. */ |
| 2010 for (sharp_off = dollar_off + 1; |
| 2011 sharp_off < gdb_blen; |
| 2012 sharp_off++) |
| 2013 if (gdb_buf[sharp_off] == '#') |
| 2014 break; |
| 2015 } |
| 2016 else if (sharp_off >= off) |
| 2017 { |
| 2018 /* Search for '#'. */ |
| 2019 for (; sharp_off < gdb_blen; sharp_off++) |
| 2020 if (gdb_buf[sharp_off] == '#') |
| 2021 break; |
| 2022 } |
| 2023 |
| 2024 /* Got packet with checksum. */ |
| 2025 if (sharp_off + 2 <= gdb_blen) |
| 2026 break; |
| 2027 |
| 2028 off = gdb_blen; |
| 2029 if (gdb_blen == sizeof (gdb_buf)) |
| 2030 { |
| 2031 /* Packet too large, discard. */ |
| 2032 off = 0; |
| 2033 } |
| 2034 } |
| 2035 |
| 2036 /* Validate and acknowledge a packet. */ |
| 2037 { |
| 2038 unsigned char chksum = 0; |
| 2039 unsigned int i; |
| 2040 int v; |
| 2041 |
| 2042 for (i = dollar_off + 1; i < sharp_off; i++) |
| 2043 chksum += gdb_buf[i]; |
| 2044 v = hex2byte (gdb_buf + sharp_off + 1); |
| 2045 if (v != chksum) |
| 2046 { |
| 2047 term_puts ("Discard bad checksum packet\n"); |
| 2048 continue; |
| 2049 } |
| 2050 else |
| 2051 { |
| 2052 sock_write ((const unsigned char *)"+", 1); |
| 2053 break; |
| 2054 } |
| 2055 } |
| 2056 } |
| 2057 |
| 2058 if (trace_pkt > 1) |
| 2059 { |
| 2060 term_puts ("<: "); |
| 2061 term_write ((char *)gdb_buf + dollar_off, sharp_off - dollar_off + 1); |
| 2062 term_putnl (); |
| 2063 } |
| 2064 |
| 2065 cmd_off = dollar_off + 1; |
| 2066 cmd_len = sharp_off - dollar_off - 1; |
| 2067 |
| 2068 if (handle_packet (gdb_buf + dollar_off + 1, sharp_off - dollar_off - 1) == 1) |
| 2069 return 1; |
| 2070 |
| 2071 send_pkt (); |
| 2072 return 0; |
| 2073 } |
| 2074 |
| 2075 /* Display the condition given by SIG64. */ |
| 2076 |
| 2077 static void |
| 2078 display_excp (struct chf64$signal_array *sig64, struct chf$mech_array *mech) |
| 2079 { |
| 2080 unsigned int status; |
| 2081 char msg[160]; |
| 2082 unsigned short msglen; |
| 2083 $DESCRIPTOR (msg_desc, msg); |
| 2084 unsigned char outadr[4]; |
| 2085 |
| 2086 status = SYS$GETMSG (sig64->chf64$q_sig_name, &msglen, &msg_desc, 0, outadr); |
| 2087 if (status & STS$M_SUCCESS) |
| 2088 { |
| 2089 char msg2[160]; |
| 2090 unsigned short msg2len; |
| 2091 struct dsc$descriptor_s msg2_desc = |
| 2092 { sizeof (msg2), DSC$K_DTYPE_T, DSC$K_CLASS_S, msg2}; |
| 2093 msg_desc.dsc$w_length = msglen; |
| 2094 status = SYS$FAOL_64 (&msg_desc, &msg2len, &msg2_desc, |
| 2095 &sig64->chf64$q_sig_arg1); |
| 2096 if (status & STS$M_SUCCESS) |
| 2097 term_write (msg2, msg2len); |
| 2098 } |
| 2099 else |
| 2100 term_puts ("no message"); |
| 2101 term_putnl (); |
| 2102 |
| 2103 if (trace_excp > 1) |
| 2104 { |
| 2105 TERM_FAO (" Frame: !XH, Depth: !4SL, Esf: !XH!/", |
| 2106 mech->chf$q_mch_frame, mech->chf$q_mch_depth, |
| 2107 mech->chf$q_mch_esf_addr); |
| 2108 } |
| 2109 } |
| 2110 |
| 2111 /* Get all registers from current thread. */ |
| 2112 |
| 2113 static void |
| 2114 read_all_registers (struct chf$mech_array *mech) |
| 2115 { |
| 2116 struct _intstk *intstk = |
| 2117 (struct _intstk *)mech->chf$q_mch_esf_addr; |
| 2118 struct chf64$signal_array *sig64 = |
| 2119 (struct chf64$signal_array *)mech->chf$ph_mch_sig64_addr; |
| 2120 unsigned int cnt = sig64->chf64$w_sig_arg_count; |
| 2121 unsigned __int64 pc = (&sig64->chf64$q_sig_name)[cnt - 2]; |
| 2122 |
| 2123 excp_regs.ip.v = pc; |
| 2124 excp_regs.psr.v = intstk->intstk$q_ipsr; |
| 2125 /* GDB and linux expects bsp to point after the current register frame. |
| 2126 Adjust. */ |
| 2127 { |
| 2128 unsigned __int64 bsp = intstk->intstk$q_bsp; |
| 2129 unsigned int sof = intstk->intstk$q_ifs & 0x7f; |
| 2130 unsigned int delta = ((bsp >> 3) & 0x3f) + sof; |
| 2131 excp_regs.bsp.v = bsp + ((sof + delta / 0x3f) << 3); |
| 2132 } |
| 2133 excp_regs.cfm.v = intstk->intstk$q_ifs & 0x3fffffffff; |
| 2134 excp_regs.pfs.v = intstk->intstk$q_pfs; |
| 2135 excp_regs.pr.v = intstk->intstk$q_preds; |
| 2136 excp_regs.gr[0].v = 0; |
| 2137 excp_regs.gr[1].v = intstk->intstk$q_gp; |
| 2138 excp_regs.gr[2].v = intstk->intstk$q_r2; |
| 2139 excp_regs.gr[3].v = intstk->intstk$q_r3; |
| 2140 excp_regs.gr[4].v = intstk->intstk$q_r4; |
| 2141 excp_regs.gr[5].v = intstk->intstk$q_r5; |
| 2142 excp_regs.gr[6].v = intstk->intstk$q_r6; |
| 2143 excp_regs.gr[7].v = intstk->intstk$q_r7; |
| 2144 excp_regs.gr[8].v = intstk->intstk$q_r8; |
| 2145 excp_regs.gr[9].v = intstk->intstk$q_r9; |
| 2146 excp_regs.gr[10].v = intstk->intstk$q_r10; |
| 2147 excp_regs.gr[11].v = intstk->intstk$q_r11; |
| 2148 excp_regs.gr[12].v = (unsigned __int64)intstk + intstk->intstk$l_stkalign; |
| 2149 excp_regs.gr[13].v = intstk->intstk$q_r13; |
| 2150 excp_regs.gr[14].v = intstk->intstk$q_r14; |
| 2151 excp_regs.gr[15].v = intstk->intstk$q_r15; |
| 2152 excp_regs.gr[16].v = intstk->intstk$q_r16; |
| 2153 excp_regs.gr[17].v = intstk->intstk$q_r17; |
| 2154 excp_regs.gr[18].v = intstk->intstk$q_r18; |
| 2155 excp_regs.gr[19].v = intstk->intstk$q_r19; |
| 2156 excp_regs.gr[20].v = intstk->intstk$q_r20; |
| 2157 excp_regs.gr[21].v = intstk->intstk$q_r21; |
| 2158 excp_regs.gr[22].v = intstk->intstk$q_r22; |
| 2159 excp_regs.gr[23].v = intstk->intstk$q_r23; |
| 2160 excp_regs.gr[24].v = intstk->intstk$q_r24; |
| 2161 excp_regs.gr[25].v = intstk->intstk$q_r25; |
| 2162 excp_regs.gr[26].v = intstk->intstk$q_r26; |
| 2163 excp_regs.gr[27].v = intstk->intstk$q_r27; |
| 2164 excp_regs.gr[28].v = intstk->intstk$q_r28; |
| 2165 excp_regs.gr[29].v = intstk->intstk$q_r29; |
| 2166 excp_regs.gr[30].v = intstk->intstk$q_r30; |
| 2167 excp_regs.gr[31].v = intstk->intstk$q_r31; |
| 2168 excp_regs.br[0].v = intstk->intstk$q_b0; |
| 2169 excp_regs.br[1].v = intstk->intstk$q_b1; |
| 2170 excp_regs.br[2].v = intstk->intstk$q_b2; |
| 2171 excp_regs.br[3].v = intstk->intstk$q_b3; |
| 2172 excp_regs.br[4].v = intstk->intstk$q_b4; |
| 2173 excp_regs.br[5].v = intstk->intstk$q_b5; |
| 2174 excp_regs.br[6].v = intstk->intstk$q_b6; |
| 2175 excp_regs.br[7].v = intstk->intstk$q_b7; |
| 2176 } |
| 2177 |
| 2178 /* Write all registers to current thread. FIXME: not yet complete. */ |
| 2179 |
| 2180 static void |
| 2181 write_all_registers (struct chf$mech_array *mech) |
| 2182 { |
| 2183 struct _intstk *intstk = |
| 2184 (struct _intstk *)mech->chf$q_mch_esf_addr; |
| 2185 |
| 2186 intstk->intstk$q_ipsr = excp_regs.psr.v; |
| 2187 } |
| 2188 |
| 2189 /* Do debugging. Report status to gdb and execute commands. */ |
| 2190 |
| 2191 static void |
| 2192 do_debug (struct chf$mech_array *mech) |
| 2193 { |
| 2194 struct _intstk *intstk = |
| 2195 (struct _intstk *)mech->chf$q_mch_esf_addr; |
| 2196 unsigned int old_ast; |
| 2197 unsigned int old_sch; |
| 2198 unsigned int status; |
| 2199 |
| 2200 /* Disable ast. */ |
| 2201 status = sys$setast (0); |
| 2202 switch (status) |
| 2203 { |
| 2204 case SS$_WASCLR: |
| 2205 old_ast = 0; |
| 2206 break; |
| 2207 case SS$_WASSET: |
| 2208 old_ast = 1; |
| 2209 break; |
| 2210 default: |
| 2211 /* Should never happen! */ |
| 2212 lib$signal (status); |
| 2213 } |
| 2214 |
| 2215 /* Disable thread scheduling. */ |
| 2216 if (has_threads) |
| 2217 old_sch = set_thread_scheduling (0); |
| 2218 |
| 2219 read_all_registers (mech); |
| 2220 |
| 2221 /* Send stop reply packet. */ |
| 2222 packet_status (); |
| 2223 send_pkt (); |
| 2224 |
| 2225 while (one_command () == 0) |
| 2226 ; |
| 2227 |
| 2228 write_all_registers (mech); |
| 2229 |
| 2230 /* Re-enable scheduling. */ |
| 2231 if (has_threads) |
| 2232 set_thread_scheduling (old_sch); |
| 2233 |
| 2234 /* Re-enable AST. */ |
| 2235 status = sys$setast (old_ast); |
| 2236 if (!(status & STS$M_SUCCESS)) |
| 2237 LIB$SIGNAL (status); |
| 2238 } |
| 2239 |
| 2240 /* The condition handler. That's the core of the stub. */ |
| 2241 |
| 2242 static int |
| 2243 excp_handler (struct chf$signal_array *sig, |
| 2244 struct chf$mech_array *mech) |
| 2245 { |
| 2246 struct chf64$signal_array *sig64 = |
| 2247 (struct chf64$signal_array *)mech->chf$ph_mch_sig64_addr; |
| 2248 unsigned int code = sig->chf$l_sig_name & STS$M_COND_ID; |
| 2249 unsigned int cnt = sig64->chf64$w_sig_arg_count; |
| 2250 unsigned __int64 pc; |
| 2251 unsigned int ret; |
| 2252 /* Self protection. FIXME: Should be per thread ? */ |
| 2253 static int in_handler = 0; |
| 2254 |
| 2255 /* Completly ignore some conditions (signaled indirectly by this stub). */ |
| 2256 switch (code) |
| 2257 { |
| 2258 case LIB$_KEYNOTFOU & STS$M_COND_ID: |
| 2259 return SS$_RESIGNAL_64; |
| 2260 default: |
| 2261 break; |
| 2262 } |
| 2263 |
| 2264 /* Protect against recursion. */ |
| 2265 in_handler++; |
| 2266 if (in_handler > 1) |
| 2267 { |
| 2268 if (in_handler == 2) |
| 2269 TERM_FAO ("gdbstub: exception in handler (pc=!XH)!!!/", |
| 2270 (&sig64->chf64$q_sig_name)[cnt - 2]); |
| 2271 sys$exit (sig->chf$l_sig_name); |
| 2272 } |
| 2273 |
| 2274 pc = (&sig64->chf64$q_sig_name)[cnt - 2]; |
| 2275 if (trace_excp) |
| 2276 TERM_FAO ("excp_handler: code: !XL, pc=!XH!/", code, pc); |
| 2277 |
| 2278 /* If break on the entry point, restore the bundle. */ |
| 2279 if (code == (SS$_BREAK & STS$M_COND_ID) |
| 2280 && pc == entry_pc |
| 2281 && entry_pc != 0) |
| 2282 { |
| 2283 static unsigned int entry_prot; |
| 2284 |
| 2285 if (trace_entry) |
| 2286 term_puts ("initial entry breakpoint\n"); |
| 2287 page_set_rw (entry_pc, 16, &entry_prot); |
| 2288 |
| 2289 ots$move ((void *)entry_pc, 16, entry_saved); |
| 2290 __fc (entry_pc); |
| 2291 page_restore_rw (entry_pc, 16, entry_prot); |
| 2292 } |
| 2293 |
| 2294 switch (code) |
| 2295 { |
| 2296 case SS$_ACCVIO & STS$M_COND_ID: |
| 2297 if (trace_excp <= 1) |
| 2298 display_excp (sig64, mech); |
| 2299 /* Fall through. */ |
| 2300 case SS$_BREAK & STS$M_COND_ID: |
| 2301 case SS$_OPCDEC & STS$M_COND_ID: |
| 2302 case SS$_TBIT & STS$M_COND_ID: |
| 2303 case SS$_DEBUG & STS$M_COND_ID: |
| 2304 if (trace_excp > 1) |
| 2305 { |
| 2306 int i; |
| 2307 struct _intstk *intstk = |
| 2308 (struct _intstk *)mech->chf$q_mch_esf_addr; |
| 2309 |
| 2310 display_excp (sig64, mech); |
| 2311 |
| 2312 TERM_FAO (" intstk: !XH!/", intstk); |
| 2313 for (i = 0; i < cnt + 1; i++) |
| 2314 TERM_FAO (" !XH!/", ((unsigned __int64 *)sig64)[i]); |
| 2315 } |
| 2316 do_debug (mech); |
| 2317 ret = SS$_CONTINUE_64; |
| 2318 break; |
| 2319 |
| 2320 default: |
| 2321 display_excp (sig64, mech); |
| 2322 ret = SS$_RESIGNAL_64; |
| 2323 break; |
| 2324 } |
| 2325 |
| 2326 in_handler--; |
| 2327 /* Discard selected thread registers. */ |
| 2328 sel_regs_pthread = 0; |
| 2329 return ret; |
| 2330 } |
| 2331 |
| 2332 /* Setup internal trace flags according to GDBSTUB$TRACE logical. */ |
| 2333 |
| 2334 static void |
| 2335 trace_init (void) |
| 2336 { |
| 2337 unsigned int status, i, start; |
| 2338 unsigned short len; |
| 2339 char resstring[LNM$C_NAMLENGTH]; |
| 2340 static const $DESCRIPTOR (tabdesc, "LNM$DCL_LOGICAL"); |
| 2341 static const $DESCRIPTOR (logdesc, "GDBSTUB$TRACE"); |
| 2342 $DESCRIPTOR (sub_desc, resstring); |
| 2343 ILE3 item_lst[2]; |
| 2344 |
| 2345 item_lst[0].ile3$w_length = LNM$C_NAMLENGTH; |
| 2346 item_lst[0].ile3$w_code = LNM$_STRING; |
| 2347 item_lst[0].ile3$ps_bufaddr = resstring; |
| 2348 item_lst[0].ile3$ps_retlen_addr = &len; |
| 2349 item_lst[1].ile3$w_length = 0; |
| 2350 item_lst[1].ile3$w_code = 0; |
| 2351 |
| 2352 /* Translate the logical name. */ |
| 2353 status = SYS$TRNLNM (0, /* Attributes of the logical name. */ |
| 2354 (void *)&tabdesc, /* Logical name table. */ |
| 2355 (void *)&logdesc, /* Logical name. */ |
| 2356 0, /* Access mode. */ |
| 2357 &item_lst); /* Item list. */ |
| 2358 if (status == SS$_NOLOGNAM) |
| 2359 return; |
| 2360 if (!(status & STS$M_SUCCESS)) |
| 2361 LIB$SIGNAL (status); |
| 2362 |
| 2363 start = 0; |
| 2364 for (i = 0; i <= len; i++) |
| 2365 { |
| 2366 if ((i == len || resstring[i] == ',' || resstring[i] == ';') |
| 2367 && i != start) |
| 2368 { |
| 2369 int j; |
| 2370 |
| 2371 sub_desc.dsc$a_pointer = resstring + start; |
| 2372 sub_desc.dsc$w_length = i - start; |
| 2373 |
| 2374 for (j = 0; j < NBR_DEBUG_FLAGS; j++) |
| 2375 if (str$case_blind_compare (&sub_desc, |
| 2376 (void *)&debug_flags[j].name) == 0) |
| 2377 { |
| 2378 debug_flags[j].val++; |
| 2379 break; |
| 2380 } |
| 2381 if (j == NBR_DEBUG_FLAGS) |
| 2382 TERM_FAO ("GDBSTUB$TRACE: unknown directive !AS!/", &sub_desc); |
| 2383 |
| 2384 start = i + 1; |
| 2385 } |
| 2386 } |
| 2387 |
| 2388 TERM_FAO ("GDBSTUB$TRACE=!AD ->", len, resstring); |
| 2389 for (i = 0; i < NBR_DEBUG_FLAGS; i++) |
| 2390 if (debug_flags[i].val > 0) |
| 2391 TERM_FAO (" !AS=!ZL", &debug_flags[i].name, debug_flags[i].val); |
| 2392 term_putnl (); |
| 2393 } |
| 2394 |
| 2395 |
| 2396 /* Entry point. */ |
| 2397 |
| 2398 static int |
| 2399 stub_start (unsigned __int64 *progxfer, void *cli_util, |
| 2400 EIHD *imghdr, IFD *imgfile, |
| 2401 unsigned int linkflag, unsigned int cliflag) |
| 2402 { |
| 2403 static int initialized; |
| 2404 int i; |
| 2405 int cnt; |
| 2406 int is_attached; |
| 2407 IMCB *imcb; |
| 2408 if (initialized) |
| 2409 term_puts ("gdbstub: re-entry\n"); |
| 2410 else |
| 2411 initialized = 1; |
| 2412 |
| 2413 /* When attached (through SS$_DEBUG condition), the number of arguments |
| 2414 is 4 and PROGXFER is the PC at interruption. */ |
| 2415 va_count (cnt); |
| 2416 is_attached = cnt == 4; |
| 2417 |
| 2418 term_init (); |
| 2419 |
| 2420 /* Hello banner. */ |
| 2421 term_puts ("Hello from gdb stub\n"); |
| 2422 |
| 2423 trace_init (); |
| 2424 |
| 2425 if (trace_entry && !is_attached) |
| 2426 { |
| 2427 TERM_FAO ("xfer: !XH, imghdr: !XH, ifd: !XH!/", |
| 2428 progxfer, imghdr, imgfile); |
| 2429 for (i = -2; i < 8; i++) |
| 2430 TERM_FAO (" at !2SW: !XH!/", i, progxfer[i]); |
| 2431 } |
| 2432 |
| 2433 /* Search for entry point. */ |
| 2434 if (!is_attached) |
| 2435 { |
| 2436 entry_pc = 0; |
| 2437 for (i = 0; progxfer[i]; i++) |
| 2438 entry_pc = progxfer[i]; |
| 2439 |
| 2440 if (trace_entry) |
| 2441 { |
| 2442 if (entry_pc == 0) |
| 2443 { |
| 2444 term_puts ("No entry point\n"); |
| 2445 return 0; |
| 2446 } |
| 2447 else |
| 2448 TERM_FAO ("Entry: !XH!/",entry_pc); |
| 2449 } |
| 2450 } |
| 2451 else |
| 2452 entry_pc = progxfer[0]; |
| 2453 |
| 2454 has_threads = 0; |
| 2455 for (imcb = ctl$gl_imglstptr->imcb$l_flink; |
| 2456 imcb != ctl$gl_imglstptr; |
| 2457 imcb = imcb->imcb$l_flink) |
| 2458 { |
| 2459 if (ots$strcmp_eql (pthread_rtl_desc.dsc$a_pointer, |
| 2460 pthread_rtl_desc.dsc$w_length, |
| 2461 imcb->imcb$t_log_image_name + 1, |
| 2462 imcb->imcb$t_log_image_name[0])) |
| 2463 has_threads = 1; |
| 2464 |
| 2465 if (trace_images) |
| 2466 { |
| 2467 unsigned int j; |
| 2468 LDRIMG *ldrimg = imcb->imcb$l_ldrimg; |
| 2469 LDRISD *ldrisd; |
| 2470 |
| 2471 TERM_FAO ("!XA-!XA ", |
| 2472 imcb->imcb$l_starting_address, |
| 2473 imcb->imcb$l_end_address); |
| 2474 |
| 2475 switch (imcb->imcb$b_act_code) |
| 2476 { |
| 2477 case IMCB$K_MAIN_PROGRAM: |
| 2478 term_puts ("prog"); |
| 2479 break; |
| 2480 case IMCB$K_MERGED_IMAGE: |
| 2481 term_puts ("mrge"); |
| 2482 break; |
| 2483 case IMCB$K_GLOBAL_IMAGE_SECTION: |
| 2484 term_puts ("glob"); |
| 2485 break; |
| 2486 default: |
| 2487 term_puts ("????"); |
| 2488 } |
| 2489 TERM_FAO (" !AD !40AC!/", |
| 2490 1, "KESU" + (imcb->imcb$b_access_mode & 3), |
| 2491 imcb->imcb$t_log_image_name); |
| 2492 |
| 2493 if ((long) ldrimg < 0 || trace_images < 2) |
| 2494 continue; |
| 2495 ldrisd = ldrimg->ldrimg$l_segments; |
| 2496 for (j = 0; j < ldrimg->ldrimg$l_segcount; j++) |
| 2497 { |
| 2498 unsigned int flags = ldrisd[j].ldrisd$i_flags; |
| 2499 term_puts (" "); |
| 2500 term_putc (flags & 0x04 ? 'R' : '-'); |
| 2501 term_putc (flags & 0x02 ? 'W' : '-'); |
| 2502 term_putc (flags & 0x01 ? 'X' : '-'); |
| 2503 term_puts (flags & 0x01000000 ? " Prot" : " "); |
| 2504 term_puts (flags & 0x04000000 ? " Shrt" : " "); |
| 2505 term_puts (flags & 0x08000000 ? " Shrd" : " "); |
| 2506 TERM_FAO (" !XA-!XA!/", |
| 2507 ldrisd[j].ldrisd$p_base, |
| 2508 (unsigned __int64) ldrisd[j].ldrisd$p_base |
| 2509 + ldrisd[j].ldrisd$i_len - 1); |
| 2510 } |
| 2511 ldrisd = ldrimg->ldrimg$l_dyn_seg; |
| 2512 if (ldrisd) |
| 2513 TERM_FAO (" dynamic !XA-!XA!/", |
| 2514 ldrisd->ldrisd$p_base, |
| 2515 (unsigned __int64) ldrisd->ldrisd$p_base |
| 2516 + ldrisd->ldrisd$i_len - 1); |
| 2517 } |
| 2518 } |
| 2519 |
| 2520 if (has_threads) |
| 2521 threads_init (); |
| 2522 |
| 2523 /* Wait for connection. */ |
| 2524 sock_init (); |
| 2525 |
| 2526 /* Set primary exception vector. */ |
| 2527 { |
| 2528 unsigned int status; |
| 2529 status = sys$setexv (0, excp_handler, PSL$C_USER, (__void_ptr32) &prevhnd); |
| 2530 if (!(status & STS$M_SUCCESS)) |
| 2531 LIB$SIGNAL (status); |
| 2532 } |
| 2533 |
| 2534 if (is_attached) |
| 2535 { |
| 2536 return excp_handler ((struct chf$signal_array *) progxfer[2], |
| 2537 (struct chf$mech_array *) progxfer[3]); |
| 2538 } |
| 2539 |
| 2540 /* Change first instruction to set a breakpoint. */ |
| 2541 { |
| 2542 /* |
| 2543 01 08 00 40 00 00 [MII] break.m 0x80001 |
| 2544 00 00 00 02 00 00 nop.i 0x0 |
| 2545 00 00 04 00 nop.i 0x0;; |
| 2546 */ |
| 2547 static const unsigned char initbp[16] = |
| 2548 { 0x01, 0x08, 0x00, 0x40, 0x00, 0x00, |
| 2549 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, |
| 2550 0x00, 0x00, 0x04, 0x00 }; |
| 2551 unsigned int entry_prot; |
| 2552 unsigned int status; |
| 2553 |
| 2554 status = page_set_rw (entry_pc, 16, &entry_prot); |
| 2555 |
| 2556 if (!(status & STS$M_SUCCESS)) |
| 2557 { |
| 2558 if ((status & STS$M_COND_ID) == (SS$_NOT_PROCESS_VA & STS$M_COND_ID)) |
| 2559 { |
| 2560 /* Cannot write here. This can happen when pthreads are |
| 2561 used. */ |
| 2562 entry_pc = 0; |
| 2563 term_puts ("gdbstub: cannot set breakpoint on entry\n"); |
| 2564 } |
| 2565 else |
| 2566 LIB$SIGNAL (status); |
| 2567 } |
| 2568 |
| 2569 if (entry_pc != 0) |
| 2570 { |
| 2571 ots$move (entry_saved, 16, (void *)entry_pc); |
| 2572 ots$move ((void *)entry_pc, 16, (void *)initbp); |
| 2573 __fc (entry_pc); |
| 2574 page_restore_rw (entry_pc, 16, entry_prot); |
| 2575 } |
| 2576 } |
| 2577 |
| 2578 /* If it wasn't possible to set a breakpoint on the entry point, |
| 2579 accept gdb commands now. Note that registers are not updated. */ |
| 2580 if (entry_pc == 0) |
| 2581 { |
| 2582 while (one_command () == 0) |
| 2583 ; |
| 2584 } |
| 2585 |
| 2586 /* We will see! */ |
| 2587 return SS$_CONTINUE; |
| 2588 } |
| 2589 |
| 2590 /* Declare the entry point of this relocatable module. */ |
| 2591 |
| 2592 struct xfer_vector |
| 2593 { |
| 2594 __int64 impure_start; |
| 2595 __int64 impure_end; |
| 2596 int (*entry) (); |
| 2597 }; |
| 2598 |
| 2599 #pragma __extern_model save |
| 2600 #pragma __extern_model strict_refdef "XFER_PSECT" |
| 2601 struct xfer_vector xfer_vector = {0, 0, stub_start}; |
| 2602 #pragma __extern_model restore |
OLD | NEW |