1130803Smarcel/* Machine independent support for QNX Neutrino /proc (process file system) 2130803Smarcel for GDB. Written by Colin Burgess at QNX Software Systems Limited. 3130803Smarcel 4130803Smarcel Copyright 2003 Free Software Foundation, Inc. 5130803Smarcel 6130803Smarcel Contributed by QNX Software Systems Ltd. 7130803Smarcel 8130803Smarcel This file is part of GDB. 9130803Smarcel 10130803Smarcel This program is free software; you can redistribute it and/or modify 11130803Smarcel it under the terms of the GNU General Public License as published by 12130803Smarcel the Free Software Foundation; either version 2 of the License, or 13130803Smarcel (at your option) any later version. 14130803Smarcel 15130803Smarcel This program is distributed in the hope that it will be useful, 16130803Smarcel but WITHOUT ANY WARRANTY; without even the implied warranty of 17130803Smarcel MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18130803Smarcel GNU General Public License for more details. 19130803Smarcel 20130803Smarcel You should have received a copy of the GNU General Public License 21130803Smarcel along with this program; if not, write to the Free Software 22130803Smarcel Foundation, Inc., 59 Temple Place - Suite 330, 23130803Smarcel Boston, MA 02111-1307, USA. */ 24130803Smarcel 25130803Smarcel#include "defs.h" 26130803Smarcel 27130803Smarcel#include <fcntl.h> 28130803Smarcel#include <spawn.h> 29130803Smarcel#include <sys/debug.h> 30130803Smarcel#include <sys/procfs.h> 31130803Smarcel#include <sys/neutrino.h> 32130803Smarcel#include <sys/syspage.h> 33130803Smarcel#include "gdb_dirent.h" 34130803Smarcel#include <sys/netmgr.h> 35130803Smarcel 36130803Smarcel#include "gdb_string.h" 37130803Smarcel#include "gdbcore.h" 38130803Smarcel#include "inferior.h" 39130803Smarcel#include "target.h" 40130803Smarcel#include "objfiles.h" 41130803Smarcel#include "gdbthread.h" 42130803Smarcel#include "nto-tdep.h" 43130803Smarcel#include "command.h" 44130803Smarcel#include "regcache.h" 45130803Smarcel 46130803Smarcel#define NULL_PID 0 47130803Smarcel#define _DEBUG_FLAG_TRACE (_DEBUG_FLAG_TRACE_EXEC|_DEBUG_FLAG_TRACE_RD|\ 48130803Smarcel _DEBUG_FLAG_TRACE_WR|_DEBUG_FLAG_TRACE_MODIFY) 49130803Smarcel 50130803Smarcelstatic struct target_ops procfs_ops; 51130803Smarcel 52130803Smarcelint ctl_fd; 53130803Smarcel 54130803Smarcelstatic void (*ofunc) (); 55130803Smarcel 56130803Smarcelstatic procfs_run run; 57130803Smarcel 58130803Smarcelstatic void procfs_open (char *, int); 59130803Smarcel 60130803Smarcelstatic int procfs_can_run (void); 61130803Smarcel 62130803Smarcelstatic ptid_t procfs_wait (ptid_t, struct target_waitstatus *); 63130803Smarcel 64130803Smarcelstatic int procfs_xfer_memory (CORE_ADDR, char *, int, int, 65130803Smarcel struct mem_attrib *attrib, 66130803Smarcel struct target_ops *); 67130803Smarcel 68130803Smarcelstatic void procfs_fetch_registers (int); 69130803Smarcel 70130803Smarcelstatic void notice_signals (void); 71130803Smarcel 72130803Smarcelstatic void init_procfs_ops (void); 73130803Smarcel 74130803Smarcelstatic ptid_t do_attach (ptid_t ptid); 75130803Smarcel 76130803Smarcelstatic int procfs_can_use_hw_breakpoint (int, int, int); 77130803Smarcel 78130803Smarcelstatic int procfs_insert_hw_breakpoint (CORE_ADDR, char *); 79130803Smarcel 80130803Smarcelstatic int procfs_remove_hw_breakpoint (CORE_ADDR addr, char *); 81130803Smarcel 82130803Smarcelstatic int procfs_insert_hw_watchpoint (CORE_ADDR addr, int len, int type); 83130803Smarcel 84130803Smarcelstatic int procfs_remove_hw_watchpoint (CORE_ADDR addr, int len, int type); 85130803Smarcel 86130803Smarcelstatic int procfs_stopped_by_watchpoint (void); 87130803Smarcel 88130803Smarcel/* These two globals are only ever set in procfs_open(), but are 89130803Smarcel referenced elsewhere. 'nto_procfs_node' is a flag used to say 90130803Smarcel whether we are local, or we should get the current node descriptor 91130803Smarcel for the remote QNX node. */ 92130803Smarcelstatic char nto_procfs_path[PATH_MAX] = { "/proc" }; 93130803Smarcelstatic unsigned nto_procfs_node = ND_LOCAL_NODE; 94130803Smarcel 95130803Smarcel/* Return the current QNX Node, or error out. This is a simple 96130803Smarcel wrapper for the netmgr_strtond() function. The reason this 97130803Smarcel is required is because QNX node descriptors are transient so 98130803Smarcel we have to re-acquire them every time. */ 99130803Smarcelstatic unsigned 100130803Smarcelnto_node(void) 101130803Smarcel{ 102130803Smarcel unsigned node; 103130803Smarcel 104130803Smarcel if (ND_NODE_CMP(nto_procfs_node, ND_LOCAL_NODE) == 0) 105130803Smarcel return ND_LOCAL_NODE; 106130803Smarcel 107130803Smarcel node = netmgr_strtond(nto_procfs_path,0); 108130803Smarcel if (node == -1) 109130803Smarcel error ("Lost the QNX node. Debug session probably over."); 110130803Smarcel 111130803Smarcel return (node); 112130803Smarcel} 113130803Smarcel 114130803Smarcel/* This is called when we call 'target procfs <arg>' from the (gdb) prompt. 115130803Smarcel For QNX6 (nto), the only valid arg will be a QNX node string, 116130803Smarcel eg: "/net/some_node". If arg is not a valid QNX node, we will 117130803Smarcel default to local. */ 118130803Smarcelstatic void 119130803Smarcelprocfs_open (char *arg, int from_tty) 120130803Smarcel{ 121130803Smarcel char *nodestr; 122130803Smarcel char *endstr; 123130803Smarcel char buffer[50]; 124130803Smarcel int fd, total_size; 125130803Smarcel procfs_sysinfo *sysinfo; 126130803Smarcel 127130803Smarcel /* Set the default node used for spawning to this one, 128130803Smarcel and only override it if there is a valid arg. */ 129130803Smarcel 130130803Smarcel nto_procfs_node = ND_LOCAL_NODE; 131130803Smarcel nodestr = arg ? xstrdup (arg) : arg; 132130803Smarcel 133130803Smarcel init_thread_list (); 134130803Smarcel 135130803Smarcel if (nodestr) 136130803Smarcel { 137130803Smarcel nto_procfs_node = netmgr_strtond (nodestr, &endstr); 138130803Smarcel if (nto_procfs_node == -1) 139130803Smarcel { 140130803Smarcel if (errno == ENOTSUP) 141130803Smarcel printf_filtered ("QNX Net Manager not found.\n"); 142130803Smarcel printf_filtered ("Invalid QNX node %s: error %d (%s).\n", nodestr, 143130803Smarcel errno, safe_strerror (errno)); 144130803Smarcel xfree (nodestr); 145130803Smarcel nodestr = NULL; 146130803Smarcel nto_procfs_node = ND_LOCAL_NODE; 147130803Smarcel } 148130803Smarcel else if (*endstr) 149130803Smarcel { 150130803Smarcel if (*(endstr - 1) == '/') 151130803Smarcel *(endstr - 1) = 0; 152130803Smarcel else 153130803Smarcel *endstr = 0; 154130803Smarcel } 155130803Smarcel } 156130803Smarcel snprintf (nto_procfs_path, PATH_MAX - 1, "%s%s", nodestr ? nodestr : "", "/proc"); 157130803Smarcel if (nodestr) 158130803Smarcel xfree (nodestr); 159130803Smarcel 160130803Smarcel fd = open (nto_procfs_path, O_RDONLY); 161130803Smarcel if (fd == -1) 162130803Smarcel { 163130803Smarcel printf_filtered ("Error opening %s : %d (%s)\n", nto_procfs_path, errno, 164130803Smarcel safe_strerror (errno)); 165130803Smarcel error ("Invalid procfs arg"); 166130803Smarcel } 167130803Smarcel 168130803Smarcel sysinfo = (void *) buffer; 169130803Smarcel if (devctl (fd, DCMD_PROC_SYSINFO, sysinfo, sizeof buffer, 0) != EOK) 170130803Smarcel { 171130803Smarcel printf_filtered ("Error getting size: %d (%s)\n", errno, 172130803Smarcel safe_strerror (errno)); 173130803Smarcel close (fd); 174130803Smarcel error ("Devctl failed."); 175130803Smarcel } 176130803Smarcel else 177130803Smarcel { 178130803Smarcel total_size = sysinfo->total_size; 179130803Smarcel sysinfo = alloca (total_size); 180130803Smarcel if (!sysinfo) 181130803Smarcel { 182130803Smarcel printf_filtered ("Memory error: %d (%s)\n", errno, 183130803Smarcel safe_strerror (errno)); 184130803Smarcel close (fd); 185130803Smarcel error ("alloca failed."); 186130803Smarcel } 187130803Smarcel else 188130803Smarcel { 189130803Smarcel if (devctl (fd, DCMD_PROC_SYSINFO, sysinfo, total_size, 0) != EOK) 190130803Smarcel { 191130803Smarcel printf_filtered ("Error getting sysinfo: %d (%s)\n", errno, 192130803Smarcel safe_strerror (errno)); 193130803Smarcel close (fd); 194130803Smarcel error ("Devctl failed."); 195130803Smarcel } 196130803Smarcel else 197130803Smarcel { 198130803Smarcel if (sysinfo->type != 199130803Smarcel nto_map_arch_to_cputype (TARGET_ARCHITECTURE->arch_name)) 200130803Smarcel { 201130803Smarcel close (fd); 202130803Smarcel error ("Invalid target CPU."); 203130803Smarcel } 204130803Smarcel } 205130803Smarcel } 206130803Smarcel } 207130803Smarcel close (fd); 208130803Smarcel printf_filtered ("Debugging using %s\n", nto_procfs_path); 209130803Smarcel} 210130803Smarcel 211130803Smarcelstatic void 212130803Smarcelprocfs_set_thread (ptid_t ptid) 213130803Smarcel{ 214130803Smarcel pid_t tid; 215130803Smarcel 216130803Smarcel tid = ptid_get_tid (ptid); 217130803Smarcel devctl (ctl_fd, DCMD_PROC_CURTHREAD, &tid, sizeof (tid), 0); 218130803Smarcel} 219130803Smarcel 220130803Smarcel/* Return nonzero if the thread TH is still alive. */ 221130803Smarcelstatic int 222130803Smarcelprocfs_thread_alive (ptid_t ptid) 223130803Smarcel{ 224130803Smarcel pid_t tid; 225130803Smarcel 226130803Smarcel tid = ptid_get_tid (ptid); 227130803Smarcel if (devctl (ctl_fd, DCMD_PROC_CURTHREAD, &tid, sizeof (tid), 0) == EOK) 228130803Smarcel return 1; 229130803Smarcel return 0; 230130803Smarcel} 231130803Smarcel 232130803Smarcelvoid 233130803Smarcelprocfs_find_new_threads (void) 234130803Smarcel{ 235130803Smarcel procfs_status status; 236130803Smarcel pid_t pid; 237130803Smarcel ptid_t ptid; 238130803Smarcel 239130803Smarcel if (ctl_fd == -1) 240130803Smarcel return; 241130803Smarcel 242130803Smarcel pid = ptid_get_pid (inferior_ptid); 243130803Smarcel 244130803Smarcel for (status.tid = 1;; ++status.tid) 245130803Smarcel { 246130803Smarcel if (devctl (ctl_fd, DCMD_PROC_TIDSTATUS, &status, sizeof (status), 0) 247130803Smarcel != EOK && status.tid != 0) 248130803Smarcel break; 249130803Smarcel ptid = ptid_build (pid, 0, status.tid); 250130803Smarcel if (!in_thread_list (ptid)) 251130803Smarcel add_thread (ptid); 252130803Smarcel } 253130803Smarcel return; 254130803Smarcel} 255130803Smarcel 256130803Smarcelvoid 257130803Smarcelprocfs_pidlist (char *args, int from_tty) 258130803Smarcel{ 259130803Smarcel DIR *dp = NULL; 260130803Smarcel struct dirent *dirp = NULL; 261130803Smarcel int fd = -1; 262130803Smarcel char buf[512]; 263130803Smarcel procfs_info *pidinfo = NULL; 264130803Smarcel procfs_debuginfo *info = NULL; 265130803Smarcel procfs_status *status = NULL; 266130803Smarcel pid_t num_threads = 0; 267130803Smarcel pid_t pid; 268130803Smarcel char name[512]; 269130803Smarcel 270130803Smarcel dp = opendir (nto_procfs_path); 271130803Smarcel if (dp == NULL) 272130803Smarcel { 273130803Smarcel fprintf_unfiltered (gdb_stderr, "failed to opendir \"%s\" - %d (%s)", 274130803Smarcel nto_procfs_path, errno, safe_strerror (errno)); 275130803Smarcel return; 276130803Smarcel } 277130803Smarcel 278130803Smarcel /* Start scan at first pid. */ 279130803Smarcel rewinddir (dp); 280130803Smarcel 281130803Smarcel do 282130803Smarcel { 283130803Smarcel /* Get the right pid and procfs path for the pid. */ 284130803Smarcel do 285130803Smarcel { 286130803Smarcel dirp = readdir (dp); 287130803Smarcel if (dirp == NULL) 288130803Smarcel { 289130803Smarcel closedir (dp); 290130803Smarcel return; 291130803Smarcel } 292130803Smarcel snprintf (buf, 511, "%s/%s/as", nto_procfs_path, dirp->d_name); 293130803Smarcel pid = atoi (dirp->d_name); 294130803Smarcel } 295130803Smarcel while (pid == 0); 296130803Smarcel 297130803Smarcel /* Open the procfs path. */ 298130803Smarcel fd = open (buf, O_RDONLY); 299130803Smarcel if (fd == -1) 300130803Smarcel { 301130803Smarcel fprintf_unfiltered (gdb_stderr, "failed to open %s - %d (%s)\n", 302130803Smarcel buf, errno, safe_strerror (errno)); 303130803Smarcel closedir (dp); 304130803Smarcel return; 305130803Smarcel } 306130803Smarcel 307130803Smarcel pidinfo = (procfs_info *) buf; 308130803Smarcel if (devctl (fd, DCMD_PROC_INFO, pidinfo, sizeof (buf), 0) != EOK) 309130803Smarcel { 310130803Smarcel fprintf_unfiltered (gdb_stderr, 311130803Smarcel "devctl DCMD_PROC_INFO failed - %d (%s)\n", errno, 312130803Smarcel safe_strerror (errno)); 313130803Smarcel break; 314130803Smarcel } 315130803Smarcel num_threads = pidinfo->num_threads; 316130803Smarcel 317130803Smarcel info = (procfs_debuginfo *) buf; 318130803Smarcel if (devctl (fd, DCMD_PROC_MAPDEBUG_BASE, info, sizeof (buf), 0) != EOK) 319130803Smarcel strcpy (name, "unavailable"); 320130803Smarcel else 321130803Smarcel strcpy (name, info->path); 322130803Smarcel 323130803Smarcel /* Collect state info on all the threads. */ 324130803Smarcel status = (procfs_status *) buf; 325130803Smarcel for (status->tid = 1; status->tid <= num_threads; status->tid++) 326130803Smarcel { 327130803Smarcel if (devctl (fd, DCMD_PROC_TIDSTATUS, status, sizeof (buf), 0) != EOK 328130803Smarcel && status->tid != 0) 329130803Smarcel break; 330130803Smarcel if (status->tid != 0) 331130803Smarcel printf_filtered ("%s - %d/%d\n", name, pid, status->tid); 332130803Smarcel } 333130803Smarcel close (fd); 334130803Smarcel } 335130803Smarcel while (dirp != NULL); 336130803Smarcel 337130803Smarcel close (fd); 338130803Smarcel closedir (dp); 339130803Smarcel return; 340130803Smarcel} 341130803Smarcel 342130803Smarcelvoid 343130803Smarcelprocfs_meminfo (char *args, int from_tty) 344130803Smarcel{ 345130803Smarcel procfs_mapinfo *mapinfos = NULL; 346130803Smarcel static int num_mapinfos = 0; 347130803Smarcel procfs_mapinfo *mapinfo_p, *mapinfo_p2; 348130803Smarcel int flags = ~0, err, num, i, j; 349130803Smarcel 350130803Smarcel struct 351130803Smarcel { 352130803Smarcel procfs_debuginfo info; 353130803Smarcel char buff[_POSIX_PATH_MAX]; 354130803Smarcel } map; 355130803Smarcel 356130803Smarcel struct info 357130803Smarcel { 358130803Smarcel unsigned addr; 359130803Smarcel unsigned size; 360130803Smarcel unsigned flags; 361130803Smarcel unsigned debug_vaddr; 362130803Smarcel unsigned long long offset; 363130803Smarcel }; 364130803Smarcel 365130803Smarcel struct printinfo 366130803Smarcel { 367130803Smarcel unsigned long long ino; 368130803Smarcel unsigned dev; 369130803Smarcel struct info text; 370130803Smarcel struct info data; 371130803Smarcel char name[256]; 372130803Smarcel } printme; 373130803Smarcel 374130803Smarcel /* Get the number of map entrys. */ 375130803Smarcel err = devctl (ctl_fd, DCMD_PROC_MAPINFO, NULL, 0, &num); 376130803Smarcel if (err != EOK) 377130803Smarcel { 378130803Smarcel printf ("failed devctl num mapinfos - %d (%s)\n", err, safe_strerror (err)); 379130803Smarcel return; 380130803Smarcel } 381130803Smarcel 382130803Smarcel mapinfos = xmalloc (num * sizeof (procfs_mapinfo)); 383130803Smarcel 384130803Smarcel num_mapinfos = num; 385130803Smarcel mapinfo_p = mapinfos; 386130803Smarcel 387130803Smarcel /* Fill the map entrys. */ 388130803Smarcel err = devctl (ctl_fd, DCMD_PROC_MAPINFO, mapinfo_p, num 389130803Smarcel * sizeof (procfs_mapinfo), &num); 390130803Smarcel if (err != EOK) 391130803Smarcel { 392130803Smarcel printf ("failed devctl mapinfos - %d (%s)\n", err, safe_strerror (err)); 393130803Smarcel xfree (mapinfos); 394130803Smarcel return; 395130803Smarcel } 396130803Smarcel 397130803Smarcel num = min (num, num_mapinfos); 398130803Smarcel 399130803Smarcel /* Run through the list of mapinfos, and store the data and text info 400130803Smarcel so we can print it at the bottom of the loop. */ 401130803Smarcel for (mapinfo_p = mapinfos, i = 0; i < num; i++, mapinfo_p++) 402130803Smarcel { 403130803Smarcel if (!(mapinfo_p->flags & flags)) 404130803Smarcel mapinfo_p->ino = 0; 405130803Smarcel 406130803Smarcel if (mapinfo_p->ino == 0) /* Already visited. */ 407130803Smarcel continue; 408130803Smarcel 409130803Smarcel map.info.vaddr = mapinfo_p->vaddr; 410130803Smarcel 411130803Smarcel err = devctl (ctl_fd, DCMD_PROC_MAPDEBUG, &map, sizeof (map), 0); 412130803Smarcel if (err != EOK) 413130803Smarcel continue; 414130803Smarcel 415130803Smarcel memset (&printme, 0, sizeof printme); 416130803Smarcel printme.dev = mapinfo_p->dev; 417130803Smarcel printme.ino = mapinfo_p->ino; 418130803Smarcel printme.text.addr = mapinfo_p->vaddr; 419130803Smarcel printme.text.size = mapinfo_p->size; 420130803Smarcel printme.text.flags = mapinfo_p->flags; 421130803Smarcel printme.text.offset = mapinfo_p->offset; 422130803Smarcel printme.text.debug_vaddr = map.info.vaddr; 423130803Smarcel strcpy (printme.name, map.info.path); 424130803Smarcel 425130803Smarcel /* Check for matching data. */ 426130803Smarcel for (mapinfo_p2 = mapinfos, j = 0; j < num; j++, mapinfo_p2++) 427130803Smarcel { 428130803Smarcel if (mapinfo_p2->vaddr != mapinfo_p->vaddr 429130803Smarcel && mapinfo_p2->ino == mapinfo_p->ino 430130803Smarcel && mapinfo_p2->dev == mapinfo_p->dev) 431130803Smarcel { 432130803Smarcel map.info.vaddr = mapinfo_p2->vaddr; 433130803Smarcel err = 434130803Smarcel devctl (ctl_fd, DCMD_PROC_MAPDEBUG, &map, sizeof (map), 0); 435130803Smarcel if (err != EOK) 436130803Smarcel continue; 437130803Smarcel 438130803Smarcel if (strcmp (map.info.path, printme.name)) 439130803Smarcel continue; 440130803Smarcel 441130803Smarcel /* Lower debug_vaddr is always text, if nessessary, swap. */ 442130803Smarcel if ((int) map.info.vaddr < (int) printme.text.debug_vaddr) 443130803Smarcel { 444130803Smarcel memcpy (&(printme.data), &(printme.text), 445130803Smarcel sizeof (printme.data)); 446130803Smarcel printme.text.addr = mapinfo_p2->vaddr; 447130803Smarcel printme.text.size = mapinfo_p2->size; 448130803Smarcel printme.text.flags = mapinfo_p2->flags; 449130803Smarcel printme.text.offset = mapinfo_p2->offset; 450130803Smarcel printme.text.debug_vaddr = map.info.vaddr; 451130803Smarcel } 452130803Smarcel else 453130803Smarcel { 454130803Smarcel printme.data.addr = mapinfo_p2->vaddr; 455130803Smarcel printme.data.size = mapinfo_p2->size; 456130803Smarcel printme.data.flags = mapinfo_p2->flags; 457130803Smarcel printme.data.offset = mapinfo_p2->offset; 458130803Smarcel printme.data.debug_vaddr = map.info.vaddr; 459130803Smarcel } 460130803Smarcel mapinfo_p2->ino = 0; 461130803Smarcel } 462130803Smarcel } 463130803Smarcel mapinfo_p->ino = 0; 464130803Smarcel 465130803Smarcel printf_filtered ("%s\n", printme.name); 466130803Smarcel printf_filtered ("\ttext=%08x bytes @ 0x%08x\n", printme.text.size, 467130803Smarcel printme.text.addr); 468130803Smarcel printf_filtered ("\t\tflags=%08x\n", printme.text.flags); 469130803Smarcel printf_filtered ("\t\tdebug=%08x\n", printme.text.debug_vaddr); 470130803Smarcel printf_filtered ("\t\toffset=%016llx\n", printme.text.offset); 471130803Smarcel if (printme.data.size) 472130803Smarcel { 473130803Smarcel printf_filtered ("\tdata=%08x bytes @ 0x%08x\n", printme.data.size, 474130803Smarcel printme.data.addr); 475130803Smarcel printf_filtered ("\t\tflags=%08x\n", printme.data.flags); 476130803Smarcel printf_filtered ("\t\tdebug=%08x\n", printme.data.debug_vaddr); 477130803Smarcel printf_filtered ("\t\toffset=%016llx\n", printme.data.offset); 478130803Smarcel } 479130803Smarcel printf_filtered ("\tdev=0x%x\n", printme.dev); 480130803Smarcel printf_filtered ("\tino=0x%x\n", (unsigned int) printme.ino); 481130803Smarcel } 482130803Smarcel xfree (mapinfos); 483130803Smarcel return; 484130803Smarcel} 485130803Smarcel 486130803Smarcel/* Print status information about what we're accessing. */ 487130803Smarcelstatic void 488130803Smarcelprocfs_files_info (struct target_ops *ignore) 489130803Smarcel{ 490130803Smarcel printf_unfiltered ("\tUsing the running image of %s %s via %s.\n", 491130803Smarcel attach_flag ? "attached" : "child", 492130803Smarcel target_pid_to_str (inferior_ptid), nto_procfs_path); 493130803Smarcel} 494130803Smarcel 495130803Smarcel/* Mark our target-struct as eligible for stray "run" and "attach" commands. */ 496130803Smarcelstatic int 497130803Smarcelprocfs_can_run (void) 498130803Smarcel{ 499130803Smarcel return 1; 500130803Smarcel} 501130803Smarcel 502130803Smarcel/* Attach to process PID, then initialize for debugging it. */ 503130803Smarcelstatic void 504130803Smarcelprocfs_attach (char *args, int from_tty) 505130803Smarcel{ 506130803Smarcel char *exec_file; 507130803Smarcel int pid; 508130803Smarcel 509130803Smarcel if (!args) 510130803Smarcel error_no_arg ("process-id to attach"); 511130803Smarcel 512130803Smarcel pid = atoi (args); 513130803Smarcel 514130803Smarcel if (pid == getpid ()) 515130803Smarcel error ("Attaching GDB to itself is not a good idea..."); 516130803Smarcel 517130803Smarcel if (from_tty) 518130803Smarcel { 519130803Smarcel exec_file = (char *) get_exec_file (0); 520130803Smarcel 521130803Smarcel if (exec_file) 522130803Smarcel printf_unfiltered ("Attaching to program `%s', %s\n", exec_file, 523130803Smarcel target_pid_to_str (pid_to_ptid (pid))); 524130803Smarcel else 525130803Smarcel printf_unfiltered ("Attaching to %s\n", 526130803Smarcel target_pid_to_str (pid_to_ptid (pid))); 527130803Smarcel 528130803Smarcel gdb_flush (gdb_stdout); 529130803Smarcel } 530130803Smarcel inferior_ptid = do_attach (pid_to_ptid (pid)); 531130803Smarcel push_target (&procfs_ops); 532130803Smarcel} 533130803Smarcel 534130803Smarcelstatic void 535130803Smarcelprocfs_post_attach (pid_t pid) 536130803Smarcel{ 537130803Smarcel#ifdef SOLIB_CREATE_INFERIOR_HOOK 538130803Smarcel if (exec_bfd) 539130803Smarcel SOLIB_CREATE_INFERIOR_HOOK (pid); 540130803Smarcel#endif 541130803Smarcel} 542130803Smarcel 543130803Smarcelstatic ptid_t 544130803Smarceldo_attach (ptid_t ptid) 545130803Smarcel{ 546130803Smarcel procfs_status status; 547130803Smarcel struct sigevent event; 548130803Smarcel char path[PATH_MAX]; 549130803Smarcel 550130803Smarcel snprintf (path, PATH_MAX - 1, "%s/%d/as", nto_procfs_path, PIDGET (ptid)); 551130803Smarcel ctl_fd = open (path, O_RDWR); 552130803Smarcel if (ctl_fd == -1) 553130803Smarcel error ("Couldn't open proc file %s, error %d (%s)", path, errno, 554130803Smarcel safe_strerror (errno)); 555130803Smarcel if (devctl (ctl_fd, DCMD_PROC_STOP, &status, sizeof (status), 0) != EOK) 556130803Smarcel error ("Couldn't stop process"); 557130803Smarcel 558130803Smarcel /* Define a sigevent for process stopped notification. */ 559130803Smarcel event.sigev_notify = SIGEV_SIGNAL_THREAD; 560130803Smarcel event.sigev_signo = SIGUSR1; 561130803Smarcel event.sigev_code = 0; 562130803Smarcel event.sigev_value.sival_ptr = NULL; 563130803Smarcel event.sigev_priority = -1; 564130803Smarcel devctl (ctl_fd, DCMD_PROC_EVENT, &event, sizeof (event), 0); 565130803Smarcel 566130803Smarcel if (devctl (ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0) == EOK 567130803Smarcel && status.flags & _DEBUG_FLAG_STOPPED) 568130803Smarcel SignalKill (nto_node(), PIDGET (ptid), 0, SIGCONT, 0, 0); 569130803Smarcel attach_flag = 1; 570130803Smarcel nto_init_solib_absolute_prefix (); 571130803Smarcel return ptid; 572130803Smarcel} 573130803Smarcel 574130803Smarcel/* Ask the user what to do when an interrupt is received. */ 575130803Smarcelstatic void 576130803Smarcelinterrupt_query (void) 577130803Smarcel{ 578130803Smarcel target_terminal_ours (); 579130803Smarcel 580130803Smarcel if (query ("Interrupted while waiting for the program.\n\ 581130803SmarcelGive up (and stop debugging it)? ")) 582130803Smarcel { 583130803Smarcel target_mourn_inferior (); 584130803Smarcel throw_exception (RETURN_QUIT); 585130803Smarcel } 586130803Smarcel 587130803Smarcel target_terminal_inferior (); 588130803Smarcel} 589130803Smarcel 590130803Smarcel/* The user typed ^C twice. */ 591130803Smarcelstatic void 592130803Smarcelnto_interrupt_twice (int signo) 593130803Smarcel{ 594130803Smarcel signal (signo, ofunc); 595130803Smarcel interrupt_query (); 596130803Smarcel signal (signo, nto_interrupt_twice); 597130803Smarcel} 598130803Smarcel 599130803Smarcelstatic void 600130803Smarcelnto_interrupt (int signo) 601130803Smarcel{ 602130803Smarcel /* If this doesn't work, try more severe steps. */ 603130803Smarcel signal (signo, nto_interrupt_twice); 604130803Smarcel 605130803Smarcel target_stop (); 606130803Smarcel} 607130803Smarcel 608130803Smarcelstatic ptid_t 609130803Smarcelprocfs_wait (ptid_t ptid, struct target_waitstatus *ourstatus) 610130803Smarcel{ 611130803Smarcel sigset_t set; 612130803Smarcel siginfo_t info; 613130803Smarcel procfs_status status; 614130803Smarcel static int exit_signo = 0; /* To track signals that cause termination. */ 615130803Smarcel 616130803Smarcel ourstatus->kind = TARGET_WAITKIND_SPURIOUS; 617130803Smarcel 618130803Smarcel if (ptid_equal (inferior_ptid, null_ptid)) 619130803Smarcel { 620130803Smarcel ourstatus->kind = TARGET_WAITKIND_STOPPED; 621130803Smarcel ourstatus->value.sig = TARGET_SIGNAL_0; 622130803Smarcel exit_signo = 0; 623130803Smarcel return null_ptid; 624130803Smarcel } 625130803Smarcel 626130803Smarcel sigemptyset (&set); 627130803Smarcel sigaddset (&set, SIGUSR1); 628130803Smarcel 629130803Smarcel devctl (ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0); 630130803Smarcel while (!(status.flags & _DEBUG_FLAG_ISTOP)) 631130803Smarcel { 632130803Smarcel ofunc = (void (*)()) signal (SIGINT, nto_interrupt); 633130803Smarcel sigwaitinfo (&set, &info); 634130803Smarcel signal (SIGINT, ofunc); 635130803Smarcel devctl (ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0); 636130803Smarcel } 637130803Smarcel 638130803Smarcel if (status.flags & _DEBUG_FLAG_SSTEP) 639130803Smarcel { 640130803Smarcel ourstatus->kind = TARGET_WAITKIND_STOPPED; 641130803Smarcel ourstatus->value.sig = TARGET_SIGNAL_TRAP; 642130803Smarcel } 643130803Smarcel /* Was it a breakpoint? */ 644130803Smarcel else if (status.flags & _DEBUG_FLAG_TRACE) 645130803Smarcel { 646130803Smarcel ourstatus->kind = TARGET_WAITKIND_STOPPED; 647130803Smarcel ourstatus->value.sig = TARGET_SIGNAL_TRAP; 648130803Smarcel } 649130803Smarcel else if (status.flags & _DEBUG_FLAG_ISTOP) 650130803Smarcel { 651130803Smarcel switch (status.why) 652130803Smarcel { 653130803Smarcel case _DEBUG_WHY_SIGNALLED: 654130803Smarcel ourstatus->kind = TARGET_WAITKIND_STOPPED; 655130803Smarcel ourstatus->value.sig = 656130803Smarcel target_signal_from_host (status.info.si_signo); 657130803Smarcel exit_signo = 0; 658130803Smarcel break; 659130803Smarcel case _DEBUG_WHY_FAULTED: 660130803Smarcel ourstatus->kind = TARGET_WAITKIND_STOPPED; 661130803Smarcel if (status.info.si_signo == SIGTRAP) 662130803Smarcel { 663130803Smarcel ourstatus->value.sig = 0; 664130803Smarcel exit_signo = 0; 665130803Smarcel } 666130803Smarcel else 667130803Smarcel { 668130803Smarcel ourstatus->value.sig = 669130803Smarcel target_signal_from_host (status.info.si_signo); 670130803Smarcel exit_signo = ourstatus->value.sig; 671130803Smarcel } 672130803Smarcel break; 673130803Smarcel 674130803Smarcel case _DEBUG_WHY_TERMINATED: 675130803Smarcel { 676130803Smarcel int waitval = 0; 677130803Smarcel 678130803Smarcel waitpid (PIDGET (inferior_ptid), &waitval, WNOHANG); 679130803Smarcel if (exit_signo) 680130803Smarcel { 681130803Smarcel /* Abnormal death. */ 682130803Smarcel ourstatus->kind = TARGET_WAITKIND_SIGNALLED; 683130803Smarcel ourstatus->value.sig = exit_signo; 684130803Smarcel } 685130803Smarcel else 686130803Smarcel { 687130803Smarcel /* Normal death. */ 688130803Smarcel ourstatus->kind = TARGET_WAITKIND_EXITED; 689130803Smarcel ourstatus->value.integer = WEXITSTATUS (waitval); 690130803Smarcel } 691130803Smarcel exit_signo = 0; 692130803Smarcel break; 693130803Smarcel } 694130803Smarcel 695130803Smarcel case _DEBUG_WHY_REQUESTED: 696130803Smarcel /* We are assuming a requested stop is due to a SIGINT. */ 697130803Smarcel ourstatus->kind = TARGET_WAITKIND_STOPPED; 698130803Smarcel ourstatus->value.sig = TARGET_SIGNAL_INT; 699130803Smarcel exit_signo = 0; 700130803Smarcel break; 701130803Smarcel } 702130803Smarcel } 703130803Smarcel 704130803Smarcel return inferior_ptid; 705130803Smarcel} 706130803Smarcel 707130803Smarcel/* Read the current values of the inferior's registers, both the 708130803Smarcel general register set and floating point registers (if supported) 709130803Smarcel and update gdb's idea of their current values. */ 710130803Smarcelstatic void 711130803Smarcelprocfs_fetch_registers (int regno) 712130803Smarcel{ 713130803Smarcel union 714130803Smarcel { 715130803Smarcel procfs_greg greg; 716130803Smarcel procfs_fpreg fpreg; 717130803Smarcel procfs_altreg altreg; 718130803Smarcel } 719130803Smarcel reg; 720130803Smarcel int regsize; 721130803Smarcel 722130803Smarcel procfs_set_thread (inferior_ptid); 723130803Smarcel if (devctl (ctl_fd, DCMD_PROC_GETGREG, ®, sizeof (reg), ®size) == EOK) 724130803Smarcel nto_supply_gregset ((char *) ®.greg); 725130803Smarcel if (devctl (ctl_fd, DCMD_PROC_GETFPREG, ®, sizeof (reg), ®size) 726130803Smarcel == EOK) 727130803Smarcel nto_supply_fpregset ((char *) ®.fpreg); 728130803Smarcel if (devctl (ctl_fd, DCMD_PROC_GETALTREG, ®, sizeof (reg), ®size) 729130803Smarcel == EOK) 730130803Smarcel nto_supply_altregset ((char *) ®.altreg); 731130803Smarcel} 732130803Smarcel 733130803Smarcel/* Copy LEN bytes to/from inferior's memory starting at MEMADDR 734130803Smarcel from/to debugger memory starting at MYADDR. Copy from inferior 735130803Smarcel if DOWRITE is zero or to inferior if DOWRITE is nonzero. 736130803Smarcel 737130803Smarcel Returns the length copied, which is either the LEN argument or 738130803Smarcel zero. This xfer function does not do partial moves, since procfs_ops 739130803Smarcel doesn't allow memory operations to cross below us in the target stack 740130803Smarcel anyway. */ 741130803Smarcelstatic int 742130803Smarcelprocfs_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int dowrite, 743130803Smarcel struct mem_attrib *attrib, struct target_ops *target) 744130803Smarcel{ 745130803Smarcel int nbytes = 0; 746130803Smarcel 747130803Smarcel if (lseek (ctl_fd, (off_t) memaddr, SEEK_SET) == (off_t) memaddr) 748130803Smarcel { 749130803Smarcel if (dowrite) 750130803Smarcel nbytes = write (ctl_fd, myaddr, len); 751130803Smarcel else 752130803Smarcel nbytes = read (ctl_fd, myaddr, len); 753130803Smarcel if (nbytes < 0) 754130803Smarcel nbytes = 0; 755130803Smarcel } 756130803Smarcel return (nbytes); 757130803Smarcel} 758130803Smarcel 759130803Smarcel/* Take a program previously attached to and detaches it. 760130803Smarcel The program resumes execution and will no longer stop 761130803Smarcel on signals, etc. We'd better not have left any breakpoints 762130803Smarcel in the program or it'll die when it hits one. */ 763130803Smarcelstatic void 764130803Smarcelprocfs_detach (char *args, int from_tty) 765130803Smarcel{ 766130803Smarcel int siggnal = 0; 767130803Smarcel 768130803Smarcel if (from_tty) 769130803Smarcel { 770130803Smarcel char *exec_file = get_exec_file (0); 771130803Smarcel if (exec_file == 0) 772130803Smarcel exec_file = ""; 773130803Smarcel printf_unfiltered ("Detaching from program: %s %s\n", 774130803Smarcel exec_file, target_pid_to_str (inferior_ptid)); 775130803Smarcel gdb_flush (gdb_stdout); 776130803Smarcel } 777130803Smarcel if (args) 778130803Smarcel siggnal = atoi (args); 779130803Smarcel 780130803Smarcel if (siggnal) 781130803Smarcel SignalKill (nto_node(), PIDGET (inferior_ptid), 0, siggnal, 0, 0); 782130803Smarcel 783130803Smarcel close (ctl_fd); 784130803Smarcel ctl_fd = -1; 785130803Smarcel init_thread_list (); 786130803Smarcel inferior_ptid = null_ptid; 787130803Smarcel attach_flag = 0; 788130803Smarcel unpush_target (&procfs_ops); /* Pop out of handling an inferior. */ 789130803Smarcel} 790130803Smarcel 791130803Smarcelstatic int 792130803Smarcelprocfs_breakpoint (CORE_ADDR addr, int type, int size) 793130803Smarcel{ 794130803Smarcel procfs_break brk; 795130803Smarcel 796130803Smarcel brk.type = type; 797130803Smarcel brk.addr = addr; 798130803Smarcel brk.size = size; 799130803Smarcel errno = devctl (ctl_fd, DCMD_PROC_BREAK, &brk, sizeof (brk), 0); 800130803Smarcel if (errno != EOK) 801130803Smarcel return 1; 802130803Smarcel return 0; 803130803Smarcel} 804130803Smarcel 805130803Smarcelstatic int 806130803Smarcelprocfs_insert_breakpoint (CORE_ADDR addr, char *contents_cache) 807130803Smarcel{ 808130803Smarcel return procfs_breakpoint (addr, _DEBUG_BREAK_EXEC, 0); 809130803Smarcel} 810130803Smarcel 811130803Smarcelstatic int 812130803Smarcelprocfs_remove_breakpoint (CORE_ADDR addr, char *contents_cache) 813130803Smarcel{ 814130803Smarcel return procfs_breakpoint (addr, _DEBUG_BREAK_EXEC, -1); 815130803Smarcel} 816130803Smarcel 817130803Smarcelstatic int 818130803Smarcelprocfs_insert_hw_breakpoint (CORE_ADDR addr, char *contents_cache) 819130803Smarcel{ 820130803Smarcel return procfs_breakpoint (addr, _DEBUG_BREAK_EXEC | _DEBUG_BREAK_HW, 0); 821130803Smarcel} 822130803Smarcel 823130803Smarcelstatic int 824130803Smarcelprocfs_remove_hw_breakpoint (CORE_ADDR addr, char *contents_cache) 825130803Smarcel{ 826130803Smarcel return procfs_breakpoint (addr, _DEBUG_BREAK_EXEC | _DEBUG_BREAK_HW, -1); 827130803Smarcel} 828130803Smarcel 829130803Smarcelstatic void 830130803Smarcelprocfs_resume (ptid_t ptid, int step, enum target_signal signo) 831130803Smarcel{ 832130803Smarcel int signal_to_pass; 833130803Smarcel procfs_status status; 834130803Smarcel 835130803Smarcel if (ptid_equal (inferior_ptid, null_ptid)) 836130803Smarcel return; 837130803Smarcel 838130803Smarcel procfs_set_thread (ptid_equal (ptid, minus_one_ptid) ? inferior_ptid : 839130803Smarcel ptid); 840130803Smarcel 841130803Smarcel run.flags = _DEBUG_RUN_FAULT | _DEBUG_RUN_TRACE; 842130803Smarcel if (step) 843130803Smarcel run.flags |= _DEBUG_RUN_STEP; 844130803Smarcel 845130803Smarcel sigemptyset ((sigset_t *) &run.fault); 846130803Smarcel sigaddset ((sigset_t *) &run.fault, FLTBPT); 847130803Smarcel sigaddset ((sigset_t *) &run.fault, FLTTRACE); 848130803Smarcel sigaddset ((sigset_t *) &run.fault, FLTILL); 849130803Smarcel sigaddset ((sigset_t *) &run.fault, FLTPRIV); 850130803Smarcel sigaddset ((sigset_t *) &run.fault, FLTBOUNDS); 851130803Smarcel sigaddset ((sigset_t *) &run.fault, FLTIOVF); 852130803Smarcel sigaddset ((sigset_t *) &run.fault, FLTIZDIV); 853130803Smarcel sigaddset ((sigset_t *) &run.fault, FLTFPE); 854130803Smarcel /* Peter V will be changing this at some point. */ 855130803Smarcel sigaddset ((sigset_t *) &run.fault, FLTPAGE); 856130803Smarcel 857130803Smarcel run.flags |= _DEBUG_RUN_ARM; 858130803Smarcel 859130803Smarcel sigemptyset (&run.trace); 860130803Smarcel notice_signals (); 861130803Smarcel signal_to_pass = target_signal_to_host (signo); 862130803Smarcel 863130803Smarcel if (signal_to_pass) 864130803Smarcel { 865130803Smarcel devctl (ctl_fd, DCMD_PROC_STATUS, &status, sizeof (status), 0); 866130803Smarcel signal_to_pass = target_signal_to_host (signo); 867130803Smarcel if (status.why & (_DEBUG_WHY_SIGNALLED | _DEBUG_WHY_FAULTED)) 868130803Smarcel { 869130803Smarcel if (signal_to_pass != status.info.si_signo) 870130803Smarcel { 871130803Smarcel SignalKill (nto_node(), PIDGET (inferior_ptid), 0, signal_to_pass, 872130803Smarcel 0, 0); 873130803Smarcel run.flags |= _DEBUG_RUN_CLRFLT | _DEBUG_RUN_CLRSIG; 874130803Smarcel } 875130803Smarcel else /* Let it kill the program without telling us. */ 876130803Smarcel sigdelset (&run.trace, signal_to_pass); 877130803Smarcel } 878130803Smarcel } 879130803Smarcel else 880130803Smarcel run.flags |= _DEBUG_RUN_CLRSIG | _DEBUG_RUN_CLRFLT; 881130803Smarcel 882130803Smarcel errno = devctl (ctl_fd, DCMD_PROC_RUN, &run, sizeof (run), 0); 883130803Smarcel if (errno != EOK) 884130803Smarcel { 885130803Smarcel perror ("run error!\n"); 886130803Smarcel return; 887130803Smarcel } 888130803Smarcel} 889130803Smarcel 890130803Smarcelstatic void 891130803Smarcelprocfs_mourn_inferior (void) 892130803Smarcel{ 893130803Smarcel if (!ptid_equal (inferior_ptid, null_ptid)) 894130803Smarcel { 895130803Smarcel SignalKill (nto_node(), PIDGET (inferior_ptid), 0, SIGKILL, 0, 0); 896130803Smarcel close (ctl_fd); 897130803Smarcel } 898130803Smarcel inferior_ptid = null_ptid; 899130803Smarcel init_thread_list (); 900130803Smarcel unpush_target (&procfs_ops); 901130803Smarcel generic_mourn_inferior (); 902130803Smarcel attach_flag = 0; 903130803Smarcel} 904130803Smarcel 905130803Smarcel/* This function breaks up an argument string into an argument 906130803Smarcel vector suitable for passing to execvp(). 907130803Smarcel E.g., on "run a b c d" this routine would get as input 908130803Smarcel the string "a b c d", and as output it would fill in argv with 909130803Smarcel the four arguments "a", "b", "c", "d". The only additional 910130803Smarcel functionality is simple quoting. The gdb command: 911130803Smarcel run a "b c d" f 912130803Smarcel will fill in argv with the three args "a", "b c d", "e". */ 913130803Smarcelstatic void 914130803Smarcelbreakup_args (char *scratch, char **argv) 915130803Smarcel{ 916130803Smarcel char *pp, *cp = scratch; 917130803Smarcel char quoting = 0; 918130803Smarcel 919130803Smarcel for (;;) 920130803Smarcel { 921130803Smarcel /* Scan past leading separators. */ 922130803Smarcel quoting = 0; 923130803Smarcel while (*cp == ' ' || *cp == '\t' || *cp == '\n') 924130803Smarcel cp++; 925130803Smarcel 926130803Smarcel /* Break if at end of string. */ 927130803Smarcel if (*cp == '\0') 928130803Smarcel break; 929130803Smarcel 930130803Smarcel /* Take an arg. */ 931130803Smarcel if (*cp == '"') 932130803Smarcel { 933130803Smarcel cp++; 934130803Smarcel quoting = strchr (cp, '"') ? 1 : 0; 935130803Smarcel } 936130803Smarcel 937130803Smarcel *argv++ = cp; 938130803Smarcel 939130803Smarcel /* Scan for next arg separator. */ 940130803Smarcel pp = cp; 941130803Smarcel if (quoting) 942130803Smarcel cp = strchr (pp, '"'); 943130803Smarcel if ((cp == NULL) || (!quoting)) 944130803Smarcel cp = strchr (pp, ' '); 945130803Smarcel if (cp == NULL) 946130803Smarcel cp = strchr (pp, '\t'); 947130803Smarcel if (cp == NULL) 948130803Smarcel cp = strchr (pp, '\n'); 949130803Smarcel 950130803Smarcel /* No separators => end of string => break. */ 951130803Smarcel if (cp == NULL) 952130803Smarcel { 953130803Smarcel pp = cp; 954130803Smarcel break; 955130803Smarcel } 956130803Smarcel 957130803Smarcel /* Replace the separator with a terminator. */ 958130803Smarcel *cp++ = '\0'; 959130803Smarcel } 960130803Smarcel 961130803Smarcel /* Execv requires a null-terminated arg vector. */ 962130803Smarcel *argv = NULL; 963130803Smarcel} 964130803Smarcel 965130803Smarcelstatic void 966130803Smarcelprocfs_create_inferior (char *exec_file, char *allargs, char **env) 967130803Smarcel{ 968130803Smarcel struct inheritance inherit; 969130803Smarcel pid_t pid; 970130803Smarcel int flags, errn; 971130803Smarcel char **argv, *args; 972130803Smarcel char *in = "", *out = "", *err = ""; 973130803Smarcel int fd, fds[3]; 974130803Smarcel sigset_t set; 975130803Smarcel 976130803Smarcel argv = xmalloc (((strlen (allargs) + 1) / (unsigned) 2 + 2) * 977130803Smarcel sizeof (*argv)); 978130803Smarcel argv[0] = get_exec_file (1); 979130803Smarcel if (!argv[0]) 980130803Smarcel { 981130803Smarcel if (exec_file) 982130803Smarcel argv[0] = exec_file; 983130803Smarcel else 984130803Smarcel return; 985130803Smarcel } 986130803Smarcel 987130803Smarcel args = xstrdup (allargs); 988130803Smarcel breakup_args (args, exec_file ? &argv[1] : &argv[0]); 989130803Smarcel 990130803Smarcel argv = nto_parse_redirection (argv, &in, &out, &err); 991130803Smarcel 992130803Smarcel fds[0] = STDIN_FILENO; 993130803Smarcel fds[1] = STDOUT_FILENO; 994130803Smarcel fds[2] = STDERR_FILENO; 995130803Smarcel 996130803Smarcel /* If the user specified I/O via gdb's --tty= arg, use it, but only 997130803Smarcel if the i/o is not also being specified via redirection. */ 998130803Smarcel if (inferior_io_terminal) 999130803Smarcel { 1000130803Smarcel if (!in[0]) 1001130803Smarcel in = inferior_io_terminal; 1002130803Smarcel if (!out[0]) 1003130803Smarcel out = inferior_io_terminal; 1004130803Smarcel if (!err[0]) 1005130803Smarcel err = inferior_io_terminal; 1006130803Smarcel } 1007130803Smarcel 1008130803Smarcel if (in[0]) 1009130803Smarcel { 1010130803Smarcel fd = open (in, O_RDONLY); 1011130803Smarcel if (fd == -1) 1012130803Smarcel perror (in); 1013130803Smarcel else 1014130803Smarcel fds[0] = fd; 1015130803Smarcel } 1016130803Smarcel if (out[0]) 1017130803Smarcel { 1018130803Smarcel fd = open (out, O_WRONLY); 1019130803Smarcel if (fd == -1) 1020130803Smarcel perror (out); 1021130803Smarcel else 1022130803Smarcel fds[1] = fd; 1023130803Smarcel } 1024130803Smarcel if (err[0]) 1025130803Smarcel { 1026130803Smarcel fd = open (err, O_WRONLY); 1027130803Smarcel if (fd == -1) 1028130803Smarcel perror (err); 1029130803Smarcel else 1030130803Smarcel fds[2] = fd; 1031130803Smarcel } 1032130803Smarcel 1033130803Smarcel /* Clear any pending SIGUSR1's but keep the behavior the same. */ 1034130803Smarcel signal (SIGUSR1, signal (SIGUSR1, SIG_IGN)); 1035130803Smarcel 1036130803Smarcel sigemptyset (&set); 1037130803Smarcel sigaddset (&set, SIGUSR1); 1038130803Smarcel sigprocmask (SIG_UNBLOCK, &set, NULL); 1039130803Smarcel 1040130803Smarcel memset (&inherit, 0, sizeof (inherit)); 1041130803Smarcel 1042130803Smarcel if (ND_NODE_CMP (nto_procfs_node, ND_LOCAL_NODE) != 0) 1043130803Smarcel { 1044130803Smarcel inherit.nd = nto_node(); 1045130803Smarcel inherit.flags |= SPAWN_SETND; 1046130803Smarcel inherit.flags &= ~SPAWN_EXEC; 1047130803Smarcel } 1048130803Smarcel inherit.flags |= SPAWN_SETGROUP | SPAWN_HOLD; 1049130803Smarcel inherit.pgroup = SPAWN_NEWPGROUP; 1050130803Smarcel pid = spawnp (argv[0], 3, fds, &inherit, argv, 1051130803Smarcel ND_NODE_CMP (nto_procfs_node, ND_LOCAL_NODE) == 0 ? env : 0); 1052130803Smarcel xfree (args); 1053130803Smarcel 1054130803Smarcel sigprocmask (SIG_BLOCK, &set, NULL); 1055130803Smarcel 1056130803Smarcel if (pid == -1) 1057130803Smarcel error ("Error spawning %s: %d (%s)", argv[0], errno, safe_strerror (errno)); 1058130803Smarcel 1059130803Smarcel if (fds[0] != STDIN_FILENO) 1060130803Smarcel close (fds[0]); 1061130803Smarcel if (fds[1] != STDOUT_FILENO) 1062130803Smarcel close (fds[1]); 1063130803Smarcel if (fds[2] != STDERR_FILENO) 1064130803Smarcel close (fds[2]); 1065130803Smarcel 1066130803Smarcel inferior_ptid = do_attach (pid_to_ptid (pid)); 1067130803Smarcel 1068130803Smarcel attach_flag = 0; 1069130803Smarcel flags = _DEBUG_FLAG_KLC; /* Kill-on-Last-Close flag. */ 1070130803Smarcel errn = devctl (ctl_fd, DCMD_PROC_SET_FLAG, &flags, sizeof (flags), 0); 1071130803Smarcel if (errn != EOK) 1072130803Smarcel { 1073130803Smarcel /* FIXME: expected warning? */ 1074130803Smarcel /* warning( "Failed to set Kill-on-Last-Close flag: errno = %d(%s)\n", 1075130803Smarcel errn, strerror(errn) ); */ 1076130803Smarcel } 1077130803Smarcel push_target (&procfs_ops); 1078130803Smarcel target_terminal_init (); 1079130803Smarcel 1080130803Smarcel#ifdef SOLIB_CREATE_INFERIOR_HOOK 1081130803Smarcel if (exec_bfd != NULL 1082130803Smarcel || (symfile_objfile != NULL && symfile_objfile->obfd != NULL)) 1083130803Smarcel SOLIB_CREATE_INFERIOR_HOOK (pid); 1084130803Smarcel#endif 1085130803Smarcel} 1086130803Smarcel 1087130803Smarcelstatic void 1088130803Smarcelprocfs_stop (void) 1089130803Smarcel{ 1090130803Smarcel devctl (ctl_fd, DCMD_PROC_STOP, NULL, 0, 0); 1091130803Smarcel} 1092130803Smarcel 1093130803Smarcelstatic void 1094130803Smarcelprocfs_kill_inferior (void) 1095130803Smarcel{ 1096130803Smarcel target_mourn_inferior (); 1097130803Smarcel} 1098130803Smarcel 1099130803Smarcel/* Store register REGNO, or all registers if REGNO == -1, from the contents 1100130803Smarcel of REGISTERS. */ 1101130803Smarcelstatic void 1102130803Smarcelprocfs_prepare_to_store (void) 1103130803Smarcel{ 1104130803Smarcel} 1105130803Smarcel 1106130803Smarcel/* Fill buf with regset and return devctl cmd to do the setting. Return 1107130803Smarcel -1 if we fail to get the regset. Store size of regset in regsize. */ 1108130803Smarcelstatic int 1109130803Smarcelget_regset (int regset, char *buf, int bufsize, int *regsize) 1110130803Smarcel{ 1111130803Smarcel int dev_get, dev_set; 1112130803Smarcel switch (regset) 1113130803Smarcel { 1114130803Smarcel case NTO_REG_GENERAL: 1115130803Smarcel dev_get = DCMD_PROC_GETGREG; 1116130803Smarcel dev_set = DCMD_PROC_SETGREG; 1117130803Smarcel break; 1118130803Smarcel 1119130803Smarcel case NTO_REG_FLOAT: 1120130803Smarcel dev_get = DCMD_PROC_GETFPREG; 1121130803Smarcel dev_set = DCMD_PROC_SETFPREG; 1122130803Smarcel break; 1123130803Smarcel 1124130803Smarcel case NTO_REG_ALT: 1125130803Smarcel dev_get = DCMD_PROC_GETALTREG; 1126130803Smarcel dev_set = DCMD_PROC_SETALTREG; 1127130803Smarcel break; 1128130803Smarcel 1129130803Smarcel case NTO_REG_SYSTEM: 1130130803Smarcel default: 1131130803Smarcel return -1; 1132130803Smarcel } 1133130803Smarcel if (devctl (ctl_fd, dev_get, &buf, bufsize, regsize) != EOK) 1134130803Smarcel return -1; 1135130803Smarcel 1136130803Smarcel return dev_set; 1137130803Smarcel} 1138130803Smarcel 1139130803Smarcelvoid 1140130803Smarcelprocfs_store_registers (int regno) 1141130803Smarcel{ 1142130803Smarcel union 1143130803Smarcel { 1144130803Smarcel procfs_greg greg; 1145130803Smarcel procfs_fpreg fpreg; 1146130803Smarcel procfs_altreg altreg; 1147130803Smarcel } 1148130803Smarcel reg; 1149130803Smarcel unsigned off; 1150130803Smarcel int len, regset, regsize, dev_set, err; 1151130803Smarcel char *data; 1152130803Smarcel 1153130803Smarcel if (ptid_equal (inferior_ptid, null_ptid)) 1154130803Smarcel return; 1155130803Smarcel procfs_set_thread (inferior_ptid); 1156130803Smarcel 1157130803Smarcel if (regno == -1) 1158130803Smarcel { 1159130803Smarcel for (regset = NTO_REG_GENERAL; regset < NTO_REG_END; regset++) 1160130803Smarcel { 1161130803Smarcel dev_set = get_regset (regset, (char *) ®, 1162130803Smarcel sizeof (reg), ®size); 1163130803Smarcel if (dev_set == -1) 1164130803Smarcel continue; 1165130803Smarcel 1166130803Smarcel if (nto_regset_fill (regset, (char *) ®) == -1) 1167130803Smarcel continue; 1168130803Smarcel 1169130803Smarcel err = devctl (ctl_fd, dev_set, ®, regsize, 0); 1170130803Smarcel if (err != EOK) 1171130803Smarcel fprintf_unfiltered (gdb_stderr, 1172130803Smarcel "Warning unable to write regset %d: %s\n", 1173130803Smarcel regno, safe_strerror (err)); 1174130803Smarcel } 1175130803Smarcel } 1176130803Smarcel else 1177130803Smarcel { 1178130803Smarcel regset = nto_regset_id (regno); 1179130803Smarcel if (regset == -1) 1180130803Smarcel return; 1181130803Smarcel 1182130803Smarcel dev_set = get_regset (regset, (char *) ®, sizeof (reg), ®size); 1183130803Smarcel if (dev_set == -1) 1184130803Smarcel return; 1185130803Smarcel 1186130803Smarcel len = nto_register_area (regno, regset, &off); 1187130803Smarcel 1188130803Smarcel if (len < 1) 1189130803Smarcel return; 1190130803Smarcel 1191130803Smarcel regcache_collect (regno, (char *) ® + off); 1192130803Smarcel 1193130803Smarcel err = devctl (ctl_fd, dev_set, ®, regsize, 0); 1194130803Smarcel if (err != EOK) 1195130803Smarcel fprintf_unfiltered (gdb_stderr, 1196130803Smarcel "Warning unable to write regset %d: %s\n", regno, 1197130803Smarcel safe_strerror (err)); 1198130803Smarcel } 1199130803Smarcel} 1200130803Smarcel 1201130803Smarcelstatic void 1202130803Smarcelnotice_signals (void) 1203130803Smarcel{ 1204130803Smarcel int signo; 1205130803Smarcel 1206130803Smarcel for (signo = 1; signo < NSIG; signo++) 1207130803Smarcel { 1208130803Smarcel if (signal_stop_state (target_signal_from_host (signo)) == 0 1209130803Smarcel && signal_print_state (target_signal_from_host (signo)) == 0 1210130803Smarcel && signal_pass_state (target_signal_from_host (signo)) == 1) 1211130803Smarcel sigdelset (&run.trace, signo); 1212130803Smarcel else 1213130803Smarcel sigaddset (&run.trace, signo); 1214130803Smarcel } 1215130803Smarcel} 1216130803Smarcel 1217130803Smarcel/* When the user changes the state of gdb's signal handling via the 1218130803Smarcel "handle" command, this function gets called to see if any change 1219130803Smarcel in the /proc interface is required. It is also called internally 1220130803Smarcel by other /proc interface functions to initialize the state of 1221130803Smarcel the traced signal set. */ 1222130803Smarcelstatic void 1223130803Smarcelprocfs_notice_signals (ptid_t ptid) 1224130803Smarcel{ 1225130803Smarcel sigemptyset (&run.trace); 1226130803Smarcel notice_signals (); 1227130803Smarcel} 1228130803Smarcel 1229130803Smarcelstatic struct tidinfo * 1230130803Smarcelprocfs_thread_info (pid_t pid, short tid) 1231130803Smarcel{ 1232130803Smarcel/* NYI */ 1233130803Smarcel return NULL; 1234130803Smarcel} 1235130803Smarcel 1236130803Smarcelchar * 1237130803Smarcelprocfs_pid_to_str (ptid_t ptid) 1238130803Smarcel{ 1239130803Smarcel static char buf[1024]; 1240130803Smarcel int pid, tid, n; 1241130803Smarcel struct tidinfo *tip; 1242130803Smarcel 1243130803Smarcel pid = ptid_get_pid (ptid); 1244130803Smarcel tid = ptid_get_tid (ptid); 1245130803Smarcel 1246130803Smarcel n = snprintf (buf, 1023, "process %d", pid); 1247130803Smarcel 1248130803Smarcel#if 0 /* NYI */ 1249130803Smarcel tip = procfs_thread_info (pid, tid); 1250130803Smarcel if (tip != NULL) 1251130803Smarcel snprintf (&buf[n], 1023, " (state = 0x%02x)", tip->state); 1252130803Smarcel#endif 1253130803Smarcel 1254130803Smarcel return buf; 1255130803Smarcel} 1256130803Smarcel 1257130803Smarcelstatic void 1258130803Smarcelinit_procfs_ops (void) 1259130803Smarcel{ 1260130803Smarcel procfs_ops.to_shortname = "procfs"; 1261130803Smarcel procfs_ops.to_longname = "QNX Neutrino procfs child process"; 1262130803Smarcel procfs_ops.to_doc = 1263130803Smarcel "QNX Neutrino procfs child process (started by the \"run\" command).\n\ 1264130803Smarcel target procfs <node>"; 1265130803Smarcel procfs_ops.to_open = procfs_open; 1266130803Smarcel procfs_ops.to_attach = procfs_attach; 1267130803Smarcel procfs_ops.to_post_attach = procfs_post_attach; 1268130803Smarcel procfs_ops.to_detach = procfs_detach; 1269130803Smarcel procfs_ops.to_resume = procfs_resume; 1270130803Smarcel procfs_ops.to_wait = procfs_wait; 1271130803Smarcel procfs_ops.to_fetch_registers = procfs_fetch_registers; 1272130803Smarcel procfs_ops.to_store_registers = procfs_store_registers; 1273130803Smarcel procfs_ops.to_prepare_to_store = procfs_prepare_to_store; 1274130803Smarcel procfs_ops.to_xfer_memory = procfs_xfer_memory; 1275130803Smarcel procfs_ops.to_files_info = procfs_files_info; 1276130803Smarcel procfs_ops.to_insert_breakpoint = procfs_insert_breakpoint; 1277130803Smarcel procfs_ops.to_remove_breakpoint = procfs_remove_breakpoint; 1278130803Smarcel procfs_ops.to_can_use_hw_breakpoint = procfs_can_use_hw_breakpoint; 1279130803Smarcel procfs_ops.to_insert_hw_breakpoint = procfs_insert_hw_breakpoint; 1280130803Smarcel procfs_ops.to_remove_hw_breakpoint = procfs_remove_breakpoint; 1281130803Smarcel procfs_ops.to_insert_watchpoint = procfs_insert_hw_watchpoint; 1282130803Smarcel procfs_ops.to_remove_watchpoint = procfs_remove_hw_watchpoint; 1283130803Smarcel procfs_ops.to_stopped_by_watchpoint = procfs_stopped_by_watchpoint; 1284130803Smarcel procfs_ops.to_terminal_init = terminal_init_inferior; 1285130803Smarcel procfs_ops.to_terminal_inferior = terminal_inferior; 1286130803Smarcel procfs_ops.to_terminal_ours_for_output = terminal_ours_for_output; 1287130803Smarcel procfs_ops.to_terminal_ours = terminal_ours; 1288130803Smarcel procfs_ops.to_terminal_info = child_terminal_info; 1289130803Smarcel procfs_ops.to_kill = procfs_kill_inferior; 1290130803Smarcel procfs_ops.to_create_inferior = procfs_create_inferior; 1291130803Smarcel procfs_ops.to_mourn_inferior = procfs_mourn_inferior; 1292130803Smarcel procfs_ops.to_can_run = procfs_can_run; 1293130803Smarcel procfs_ops.to_notice_signals = procfs_notice_signals; 1294130803Smarcel procfs_ops.to_thread_alive = procfs_thread_alive; 1295130803Smarcel procfs_ops.to_find_new_threads = procfs_find_new_threads; 1296130803Smarcel procfs_ops.to_pid_to_str = procfs_pid_to_str; 1297130803Smarcel procfs_ops.to_stop = procfs_stop; 1298130803Smarcel procfs_ops.to_stratum = process_stratum; 1299130803Smarcel procfs_ops.to_has_all_memory = 1; 1300130803Smarcel procfs_ops.to_has_memory = 1; 1301130803Smarcel procfs_ops.to_has_stack = 1; 1302130803Smarcel procfs_ops.to_has_registers = 1; 1303130803Smarcel procfs_ops.to_has_execution = 1; 1304130803Smarcel procfs_ops.to_magic = OPS_MAGIC; 1305130803Smarcel procfs_ops.to_have_continuable_watchpoint = 1; 1306130803Smarcel} 1307130803Smarcel 1308130803Smarcel#define OSTYPE_NTO 1 1309130803Smarcel 1310130803Smarcelvoid 1311130803Smarcel_initialize_procfs (void) 1312130803Smarcel{ 1313130803Smarcel sigset_t set; 1314130803Smarcel 1315130803Smarcel init_procfs_ops (); 1316130803Smarcel add_target (&procfs_ops); 1317130803Smarcel 1318130803Smarcel /* We use SIGUSR1 to gain control after we block waiting for a process. 1319130803Smarcel We use sigwaitevent to wait. */ 1320130803Smarcel sigemptyset (&set); 1321130803Smarcel sigaddset (&set, SIGUSR1); 1322130803Smarcel sigprocmask (SIG_BLOCK, &set, NULL); 1323130803Smarcel 1324130803Smarcel /* Set up trace and fault sets, as gdb expects them. */ 1325130803Smarcel sigemptyset (&run.trace); 1326130803Smarcel notice_signals (); 1327130803Smarcel 1328130803Smarcel /* Stuff some information. */ 1329130803Smarcel nto_cpuinfo_flags = SYSPAGE_ENTRY (cpuinfo)->flags; 1330130803Smarcel nto_cpuinfo_valid = 1; 1331130803Smarcel 1332130803Smarcel add_info ("pidlist", procfs_pidlist, "pidlist"); 1333130803Smarcel add_info ("meminfo", procfs_meminfo, "memory information"); 1334130803Smarcel} 1335130803Smarcel 1336130803Smarcel 1337130803Smarcelstatic int 1338130803Smarcelprocfs_hw_watchpoint (int addr, int len, int type) 1339130803Smarcel{ 1340130803Smarcel procfs_break brk; 1341130803Smarcel 1342130803Smarcel switch (type) 1343130803Smarcel { 1344130803Smarcel case 1: /* Read. */ 1345130803Smarcel brk.type = _DEBUG_BREAK_RD; 1346130803Smarcel break; 1347130803Smarcel case 2: /* Read/Write. */ 1348130803Smarcel brk.type = _DEBUG_BREAK_RW; 1349130803Smarcel break; 1350130803Smarcel default: /* Modify. */ 1351130803Smarcel/* FIXME: brk.type = _DEBUG_BREAK_RWM gives EINVAL for some reason. */ 1352130803Smarcel brk.type = _DEBUG_BREAK_RW; 1353130803Smarcel } 1354130803Smarcel brk.type |= _DEBUG_BREAK_HW; /* Always ask for HW. */ 1355130803Smarcel brk.addr = addr; 1356130803Smarcel brk.size = len; 1357130803Smarcel 1358130803Smarcel errno = devctl (ctl_fd, DCMD_PROC_BREAK, &brk, sizeof (brk), 0); 1359130803Smarcel if (errno != EOK) 1360130803Smarcel { 1361130803Smarcel perror ("Failed to set hardware watchpoint"); 1362130803Smarcel return -1; 1363130803Smarcel } 1364130803Smarcel return 0; 1365130803Smarcel} 1366130803Smarcel 1367130803Smarcelstatic int 1368130803Smarcelprocfs_can_use_hw_breakpoint (int type, int cnt, int othertype) 1369130803Smarcel{ 1370130803Smarcel return 1; 1371130803Smarcel} 1372130803Smarcel 1373130803Smarcelstatic int 1374130803Smarcelprocfs_remove_hw_watchpoint (CORE_ADDR addr, int len, int type) 1375130803Smarcel{ 1376130803Smarcel return procfs_hw_watchpoint (addr, -1, type); 1377130803Smarcel} 1378130803Smarcel 1379130803Smarcelstatic int 1380130803Smarcelprocfs_insert_hw_watchpoint (CORE_ADDR addr, int len, int type) 1381130803Smarcel{ 1382130803Smarcel return procfs_hw_watchpoint (addr, len, type); 1383130803Smarcel} 1384130803Smarcel 1385130803Smarcelstatic int 1386130803Smarcelprocfs_stopped_by_watchpoint (void) 1387130803Smarcel{ 1388130803Smarcel return 0; 1389130803Smarcel} 1390