?? linux-low.c
字號:
p_sig = malloc (sizeof (*p_sig)); p_sig->prev = process->pending_signals; p_sig->signal = process->resume->sig; process->pending_signals = p_sig; } process->resume = NULL;}/* Set DUMMY if this process has an interesting status pending. */static intresume_status_pending_p (struct inferior_list_entry *entry, void *flag_p){ struct process_info *process = (struct process_info *) entry; /* Processes which will not be resumed are not interesting, because we might not wait for them next time through linux_wait. */ if (process->resume->leave_stopped) return 0; /* If this thread has a removed breakpoint, we won't have any events to report later, so check now. check_removed_breakpoint may clear status_pending_p. We avoid calling check_removed_breakpoint for any thread that we are not otherwise going to resume - this lets us preserve stopped status when two threads hit a breakpoint. GDB removes the breakpoint to single-step a particular thread past it, then re-inserts it and resumes all threads. We want to report the second thread without resuming it in the interim. */ if (process->status_pending_p) check_removed_breakpoint (process); if (process->status_pending_p) * (int *) flag_p = 1; return 0;}static voidlinux_resume (struct thread_resume *resume_info){ int pending_flag; /* Yes, the use of a global here is rather ugly. */ resume_ptr = resume_info; for_each_inferior (&all_threads, linux_set_resume_request); /* If there is a thread which would otherwise be resumed, which has a pending status, then don't resume any threads - we can just report the pending status. Make sure to queue any signals that would otherwise be sent. */ pending_flag = 0; find_inferior (&all_processes, resume_status_pending_p, &pending_flag); if (debug_threads) { if (pending_flag) fprintf (stderr, "Not resuming, pending status\n"); else fprintf (stderr, "Resuming, no pending status\n"); } if (pending_flag) for_each_inferior (&all_threads, linux_queue_one_thread); else { block_async_io (); enable_async_io (); for_each_inferior (&all_threads, linux_continue_one_thread); }}#ifdef HAVE_LINUX_USRREGSintregister_addr (int regnum){ int addr; if (regnum < 0 || regnum >= the_low_target.num_regs) error ("Invalid register number %d.", regnum); addr = the_low_target.regmap[regnum]; return addr;}/* Fetch one register. */static voidfetch_register (int regno){ CORE_ADDR regaddr; register int i; char *buf; if (regno >= the_low_target.num_regs) return; if ((*the_low_target.cannot_fetch_register) (regno)) return; regaddr = register_addr (regno); if (regaddr == -1) return; buf = alloca (register_size (regno)); for (i = 0; i < register_size (regno); i += sizeof (PTRACE_XFER_TYPE)) { errno = 0; *(PTRACE_XFER_TYPE *) (buf + i) = ptrace (PTRACE_PEEKUSER, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, 0); regaddr += sizeof (PTRACE_XFER_TYPE); if (errno != 0) { /* Warning, not error, in case we are attached; sometimes the kernel doesn't let us at the registers. */ char *err = strerror (errno); char *msg = alloca (strlen (err) + 128); sprintf (msg, "reading register %d: %s", regno, err); error (msg); goto error_exit; } } supply_register (regno, buf);error_exit:;}/* Fetch all registers, or just one, from the child process. */static voidusr_fetch_inferior_registers (int regno){ if (regno == -1 || regno == 0) for (regno = 0; regno < the_low_target.num_regs; regno++) fetch_register (regno); else fetch_register (regno);}/* Store our register values back into the inferior. If REGNO is -1, do this for all registers. Otherwise, REGNO specifies which register (so we can save time). */static voidusr_store_inferior_registers (int regno){ CORE_ADDR regaddr; int i; char *buf; if (regno >= 0) { if (regno >= the_low_target.num_regs) return; if ((*the_low_target.cannot_store_register) (regno) == 1) return; regaddr = register_addr (regno); if (regaddr == -1) return; errno = 0; buf = alloca (register_size (regno)); collect_register (regno, buf); for (i = 0; i < register_size (regno); i += sizeof (PTRACE_XFER_TYPE)) { errno = 0; ptrace (PTRACE_POKEUSER, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, *(PTRACE_XFER_TYPE *) (buf + i)); if (errno != 0) { if ((*the_low_target.cannot_store_register) (regno) == 0) { char *err = strerror (errno); char *msg = alloca (strlen (err) + 128); sprintf (msg, "writing register %d: %s", regno, err); error (msg); return; } } regaddr += sizeof (PTRACE_XFER_TYPE); } } else for (regno = 0; regno < the_low_target.num_regs; regno++) usr_store_inferior_registers (regno);}#endif /* HAVE_LINUX_USRREGS */#ifdef HAVE_LINUX_REGSETSstatic intregsets_fetch_inferior_registers (){ struct regset_info *regset; regset = target_regsets; while (regset->size >= 0) { void *buf; int res; if (regset->size == 0) { regset ++; continue; } buf = malloc (regset->size); res = ptrace (regset->get_request, inferior_pid, 0, buf); if (res < 0) { if (errno == EIO) { /* If we get EIO on the first regset, do not try regsets again. If we get EIO on a later regset, disable that regset. */ if (regset == target_regsets) { use_regsets_p = 0; return -1; } else { regset->size = 0; continue; } } else { char s[256]; sprintf (s, "ptrace(regsets_fetch_inferior_registers) PID=%d", inferior_pid); perror (s); } } regset->store_function (buf); regset ++; } return 0;}static intregsets_store_inferior_registers (){ struct regset_info *regset; regset = target_regsets; while (regset->size >= 0) { void *buf; int res; if (regset->size == 0) { regset ++; continue; } buf = malloc (regset->size); regset->fill_function (buf); res = ptrace (regset->set_request, inferior_pid, 0, buf); if (res < 0) { if (errno == EIO) { /* If we get EIO on the first regset, do not try regsets again. If we get EIO on a later regset, disable that regset. */ if (regset == target_regsets) { use_regsets_p = 0; return -1; } else { regset->size = 0; continue; } } else { perror ("Warning: ptrace(regsets_store_inferior_registers)"); } } regset ++; free (buf); } return 0;}#endif /* HAVE_LINUX_REGSETS */voidlinux_fetch_registers (int regno){#ifdef HAVE_LINUX_REGSETS if (use_regsets_p) { if (regsets_fetch_inferior_registers () == 0) return; }#endif#ifdef HAVE_LINUX_USRREGS usr_fetch_inferior_registers (regno);#endif}voidlinux_store_registers (int regno){#ifdef HAVE_LINUX_REGSETS if (use_regsets_p) { if (regsets_store_inferior_registers () == 0) return; }#endif#ifdef HAVE_LINUX_USRREGS usr_store_inferior_registers (regno);#endif}/* Copy LEN bytes from inferior's memory starting at MEMADDR to debugger memory starting at MYADDR. */static intlinux_read_memory (CORE_ADDR memaddr, char *myaddr, int len){ register int i; /* Round starting address down to longword boundary. */ register CORE_ADDR addr = memaddr & -(CORE_ADDR) sizeof (PTRACE_XFER_TYPE); /* Round ending address up; get number of longwords that makes. */ register int count = (((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1) / sizeof (PTRACE_XFER_TYPE); /* Allocate buffer of that many longwords. */ register PTRACE_XFER_TYPE *buffer = (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE)); /* Read all the longwords */ for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE)) { errno = 0; buffer[i] = ptrace (PTRACE_PEEKTEXT, inferior_pid, (PTRACE_ARG3_TYPE) addr, 0); if (errno) return errno; } /* Copy appropriate bytes out of the buffer. */ memcpy (myaddr, (char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)), len); return 0;}/* Copy LEN bytes of data from debugger memory at MYADDR to inferior's memory at MEMADDR. On failure (cannot write the inferior) returns the value of errno. */static intlinux_write_memory (CORE_ADDR memaddr, const char *myaddr, int len){ register int i; /* Round starting address down to longword boundary. */ register CORE_ADDR addr = memaddr & -(CORE_ADDR) sizeof (PTRACE_XFER_TYPE); /* Round ending address up; get number of longwords that makes. */ register int count = (((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1) / sizeof (PTRACE_XFER_TYPE); /* Allocate buffer of that many longwords. */ register PTRACE_XFER_TYPE *buffer = (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE)); extern int errno; if (debug_threads) { fprintf (stderr, "Writing %02x to %08lx\n", (unsigned)myaddr[0], (long)memaddr); } /* Fill start and end extra bytes of buffer with existing memory data. */ buffer[0] = ptrace (PTRACE_PEEKTEXT, inferior_pid, (PTRACE_ARG3_TYPE) addr, 0); if (count > 1) { buffer[count - 1] = ptrace (PTRACE_PEEKTEXT, inferior_pid, (PTRACE_ARG3_TYPE) (addr + (count - 1) * sizeof (PTRACE_XFER_TYPE)), 0); } /* Copy data to be written over corresponding part of buffer */ memcpy ((char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)), myaddr, len); /* Write the entire buffer. */ for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE)) { errno = 0; ptrace (PTRACE_POKETEXT, inferior_pid, (PTRACE_ARG3_TYPE) addr, buffer[i]); if (errno) return errno; } return 0;}static voidlinux_look_up_symbols (void){#ifdef USE_THREAD_DB if (using_threads) return; using_threads = thread_db_init ();#endif}static voidlinux_send_signal (int signum){ extern int signal_pid; if (cont_thread > 0) { struct process_info *process; process = get_thread_process (current_inferior); kill_lwp (process->lwpid, signum); } else kill_lwp (signal_pid, signum);}/* Copy LEN bytes from inferior's auxiliary vector starting at OFFSET to debugger memory starting at MYADDR. */static intlinux_read_auxv (CORE_ADDR offset, char *myaddr, unsigned int len){ char filename[PATH_MAX]; int fd, n; snprintf (filename, sizeof filename, "/proc/%d/auxv", inferior_pid); fd = open (filename, O_RDONLY); if (fd < 0) return -1; if (offset != (CORE_ADDR) 0 && lseek (fd, (off_t) offset, SEEK_SET) != (off_t) offset) n = -1; else n = read (fd, myaddr, len); close (fd); return n;}static struct target_ops linux_target_ops = { linux_create_inferior, linux_attach, linux_kill, linux_detach, linux_thread_alive, linux_resume, linux_wait, linux_fetch_registers, linux_store_registers, linux_read_memory, linux_write_memory, linux_look_up_symbols, linux_send_signal, linux_read_auxv,};static voidlinux_init_signals (){ /* FIXME drow/2002-06-09: As above, we should check with LinuxThreads to find what the cancel signal actually is. */ signal (__SIGRTMIN+1, SIG_IGN);}voidinitialize_low (void){ using_threads = 0; set_target_ops (&linux_target_ops); set_breakpoint_data (the_low_target.breakpoint, the_low_target.breakpoint_len); init_registers (); linux_init_signals ();}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -