GDBserver
|
00001 /* Copyright (C) 2009-2013 Free Software Foundation, Inc. 00002 00003 This file is part of GDB. 00004 00005 This program is free software; you can redistribute it and/or modify 00006 it under the terms of the GNU General Public License as published by 00007 the Free Software Foundation; either version 3 of the License, or 00008 (at your option) any later version. 00009 00010 This program is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 GNU General Public License for more details. 00014 00015 You should have received a copy of the GNU General Public License 00016 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 00017 00018 #include "server.h" 00019 #include "target.h" 00020 #include "lynx-low.h" 00021 00022 #include <limits.h> 00023 #include <sys/ptrace.h> 00024 #include <sys/piddef.h> /* Provides PIDGET, TIDGET, BUILDPID, etc. */ 00025 #include <unistd.h> 00026 #include <sys/ioctl.h> 00027 #include <sys/types.h> 00028 #include "gdb_wait.h" 00029 #include <signal.h> 00030 #include "filestuff.h" 00031 00032 int using_threads = 1; 00033 00034 const struct target_desc *lynx_tdesc; 00035 00036 /* Per-process private data. */ 00037 00038 struct process_info_private 00039 { 00040 /* The PTID obtained from the last wait performed on this process. 00041 Initialized to null_ptid until the first wait is performed. */ 00042 ptid_t last_wait_event_ptid; 00043 }; 00044 00045 /* Print a debug trace on standard output if debug_threads is set. */ 00046 00047 static void 00048 lynx_debug (char *string, ...) 00049 { 00050 va_list args; 00051 00052 if (!debug_threads) 00053 return; 00054 00055 va_start (args, string); 00056 fprintf (stderr, "DEBUG(lynx): "); 00057 vfprintf (stderr, string, args); 00058 fprintf (stderr, "\n"); 00059 va_end (args); 00060 } 00061 00062 /* Build a ptid_t given a PID and a LynxOS TID. */ 00063 00064 static ptid_t 00065 lynx_ptid_build (int pid, long tid) 00066 { 00067 /* brobecker/2010-06-21: It looks like the LWP field in ptids 00068 should be distinct for each thread (see write_ptid where it 00069 writes the thread ID from the LWP). So instead of storing 00070 the LynxOS tid in the tid field of the ptid, we store it in 00071 the lwp field. */ 00072 return ptid_build (pid, tid, 0); 00073 } 00074 00075 /* Return the process ID of the given PTID. 00076 00077 This function has little reason to exist, it's just a wrapper around 00078 ptid_get_pid. But since we have a getter function for the lynxos 00079 ptid, it feels cleaner to have a getter for the pid as well. */ 00080 00081 static int 00082 lynx_ptid_get_pid (ptid_t ptid) 00083 { 00084 return ptid_get_pid (ptid); 00085 } 00086 00087 /* Return the LynxOS tid of the given PTID. */ 00088 00089 static long 00090 lynx_ptid_get_tid (ptid_t ptid) 00091 { 00092 /* See lynx_ptid_build: The LynxOS tid is stored inside the lwp field 00093 of the ptid. */ 00094 return ptid_get_lwp (ptid); 00095 } 00096 00097 /* For a given PTID, return the associated PID as known by the LynxOS 00098 ptrace layer. */ 00099 00100 static int 00101 lynx_ptrace_pid_from_ptid (ptid_t ptid) 00102 { 00103 return BUILDPID (lynx_ptid_get_pid (ptid), lynx_ptid_get_tid (ptid)); 00104 } 00105 00106 /* Return a string image of the ptrace REQUEST number. */ 00107 00108 static char * 00109 ptrace_request_to_str (int request) 00110 { 00111 #define CASE(X) case X: return #X 00112 switch (request) 00113 { 00114 CASE(PTRACE_TRACEME); 00115 CASE(PTRACE_PEEKTEXT); 00116 CASE(PTRACE_PEEKDATA); 00117 CASE(PTRACE_PEEKUSER); 00118 CASE(PTRACE_POKETEXT); 00119 CASE(PTRACE_POKEDATA); 00120 CASE(PTRACE_POKEUSER); 00121 CASE(PTRACE_CONT); 00122 CASE(PTRACE_KILL); 00123 CASE(PTRACE_SINGLESTEP); 00124 CASE(PTRACE_ATTACH); 00125 CASE(PTRACE_DETACH); 00126 CASE(PTRACE_GETREGS); 00127 CASE(PTRACE_SETREGS); 00128 CASE(PTRACE_GETFPREGS); 00129 CASE(PTRACE_SETFPREGS); 00130 CASE(PTRACE_READDATA); 00131 CASE(PTRACE_WRITEDATA); 00132 CASE(PTRACE_READTEXT); 00133 CASE(PTRACE_WRITETEXT); 00134 CASE(PTRACE_GETFPAREGS); 00135 CASE(PTRACE_SETFPAREGS); 00136 CASE(PTRACE_GETWINDOW); 00137 CASE(PTRACE_SETWINDOW); 00138 CASE(PTRACE_SYSCALL); 00139 CASE(PTRACE_DUMPCORE); 00140 CASE(PTRACE_SETWRBKPT); 00141 CASE(PTRACE_SETACBKPT); 00142 CASE(PTRACE_CLRBKPT); 00143 CASE(PTRACE_GET_UCODE); 00144 #ifdef PT_READ_GPR 00145 CASE(PT_READ_GPR); 00146 #endif 00147 #ifdef PT_WRITE_GPR 00148 CASE(PT_WRITE_GPR); 00149 #endif 00150 #ifdef PT_READ_FPR 00151 CASE(PT_READ_FPR); 00152 #endif 00153 #ifdef PT_WRITE_FPR 00154 CASE(PT_WRITE_FPR); 00155 #endif 00156 #ifdef PT_READ_VPR 00157 CASE(PT_READ_VPR); 00158 #endif 00159 #ifdef PT_WRITE_VPR 00160 CASE(PT_WRITE_VPR); 00161 #endif 00162 #ifdef PTRACE_PEEKUSP 00163 CASE(PTRACE_PEEKUSP); 00164 #endif 00165 #ifdef PTRACE_POKEUSP 00166 CASE(PTRACE_POKEUSP); 00167 #endif 00168 CASE(PTRACE_PEEKTHREAD); 00169 CASE(PTRACE_THREADUSER); 00170 CASE(PTRACE_FPREAD); 00171 CASE(PTRACE_FPWRITE); 00172 CASE(PTRACE_SETSIG); 00173 CASE(PTRACE_CONT_ONE); 00174 CASE(PTRACE_KILL_ONE); 00175 CASE(PTRACE_SINGLESTEP_ONE); 00176 CASE(PTRACE_GETLOADINFO); 00177 CASE(PTRACE_GETTRACESIG); 00178 #ifdef PTRACE_GETTHREADLIST 00179 CASE(PTRACE_GETTHREADLIST); 00180 #endif 00181 } 00182 #undef CASE 00183 00184 return "<unknown-request>"; 00185 } 00186 00187 /* A wrapper around ptrace that allows us to print debug traces of 00188 ptrace calls if debug traces are activated. */ 00189 00190 static int 00191 lynx_ptrace (int request, ptid_t ptid, int addr, int data, int addr2) 00192 { 00193 int result; 00194 const int pid = lynx_ptrace_pid_from_ptid (ptid); 00195 int saved_errno; 00196 00197 if (debug_threads) 00198 fprintf (stderr, "PTRACE (%s, pid=%d(pid=%d, tid=%d), addr=0x%x, " 00199 "data=0x%x, addr2=0x%x)", 00200 ptrace_request_to_str (request), pid, PIDGET (pid), TIDGET (pid), 00201 addr, data, addr2); 00202 result = ptrace (request, pid, addr, data, addr2); 00203 saved_errno = errno; 00204 if (debug_threads) 00205 fprintf (stderr, " -> %d (=0x%x)\n", result, result); 00206 00207 errno = saved_errno; 00208 return result; 00209 } 00210 00211 /* Call add_process with the given parameters, and initializes 00212 the process' private data. */ 00213 00214 static struct process_info * 00215 lynx_add_process (int pid, int attached) 00216 { 00217 struct process_info *proc; 00218 00219 proc = add_process (pid, attached); 00220 proc->tdesc = lynx_tdesc; 00221 proc->private = xcalloc (1, sizeof (*proc->private)); 00222 proc->private->last_wait_event_ptid = null_ptid; 00223 00224 return proc; 00225 } 00226 00227 /* Implement the create_inferior method of the target_ops vector. */ 00228 00229 static int 00230 lynx_create_inferior (char *program, char **allargs) 00231 { 00232 int pid; 00233 00234 lynx_debug ("lynx_create_inferior ()"); 00235 00236 pid = fork (); 00237 if (pid < 0) 00238 perror_with_name ("fork"); 00239 00240 if (pid == 0) 00241 { 00242 int pgrp; 00243 00244 close_most_fds (); 00245 00246 /* Switch child to its own process group so that signals won't 00247 directly affect gdbserver. */ 00248 pgrp = getpid(); 00249 setpgid (0, pgrp); 00250 ioctl (0, TIOCSPGRP, &pgrp); 00251 lynx_ptrace (PTRACE_TRACEME, null_ptid, 0, 0, 0); 00252 execv (program, allargs); 00253 fprintf (stderr, "Cannot exec %s: %s.\n", program, strerror (errno)); 00254 fflush (stderr); 00255 _exit (0177); 00256 } 00257 00258 lynx_add_process (pid, 0); 00259 /* Do not add the process thread just yet, as we do not know its tid. 00260 We will add it later, during the wait for the STOP event corresponding 00261 to the lynx_ptrace (PTRACE_TRACEME) call above. */ 00262 return pid; 00263 } 00264 00265 /* Assuming we've just attached to a running inferior whose pid is PID, 00266 add all threads running in that process. */ 00267 00268 static void 00269 lynx_add_threads_after_attach (int pid) 00270 { 00271 /* Ugh! There appears to be no way to get the list of threads 00272 in the program we just attached to. So get the list by calling 00273 the "ps" command. This is only needed now, as we will then 00274 keep the thread list up to date thanks to thread creation and 00275 exit notifications. */ 00276 FILE *f; 00277 char buf[256]; 00278 int thread_pid, thread_tid; 00279 00280 f = popen ("ps atx", "r"); 00281 if (f == NULL) 00282 perror_with_name ("Cannot get thread list"); 00283 00284 while (fgets (buf, sizeof (buf), f) != NULL) 00285 if ((sscanf (buf, "%d %d", &thread_pid, &thread_tid) == 2 00286 && thread_pid == pid)) 00287 { 00288 ptid_t thread_ptid = lynx_ptid_build (pid, thread_tid); 00289 00290 if (!find_thread_ptid (thread_ptid)) 00291 { 00292 lynx_debug ("New thread: (pid = %d, tid = %d)", 00293 pid, thread_tid); 00294 add_thread (thread_ptid, NULL); 00295 } 00296 } 00297 00298 pclose (f); 00299 } 00300 00301 /* Implement the attach target_ops method. */ 00302 00303 static int 00304 lynx_attach (unsigned long pid) 00305 { 00306 ptid_t ptid = lynx_ptid_build (pid, 0); 00307 00308 if (lynx_ptrace (PTRACE_ATTACH, ptid, 0, 0, 0) != 0) 00309 error ("Cannot attach to process %lu: %s (%d)\n", pid, 00310 strerror (errno), errno); 00311 00312 lynx_add_process (pid, 1); 00313 lynx_add_threads_after_attach (pid); 00314 00315 return 0; 00316 } 00317 00318 /* Implement the resume target_ops method. */ 00319 00320 static void 00321 lynx_resume (struct thread_resume *resume_info, size_t n) 00322 { 00323 /* FIXME: Assume for now that n == 1. */ 00324 ptid_t ptid = resume_info[0].thread; 00325 const int request = (resume_info[0].kind == resume_step 00326 ? PTRACE_SINGLESTEP : PTRACE_CONT); 00327 const int signal = resume_info[0].sig; 00328 00329 /* If given a minus_one_ptid, then try using the current_process' 00330 private->last_wait_event_ptid. On most LynxOS versions, 00331 using any of the process' thread works well enough, but 00332 LynxOS 178 is a little more sensitive, and triggers some 00333 unexpected signals (Eg SIG61) when we resume the inferior 00334 using a different thread. */ 00335 if (ptid_equal (ptid, minus_one_ptid)) 00336 ptid = current_process()->private->last_wait_event_ptid; 00337 00338 /* The ptid might still be minus_one_ptid; this can happen between 00339 the moment we create the inferior or attach to a process, and 00340 the moment we resume its execution for the first time. It is 00341 fine to use the current_inferior's ptid in those cases. */ 00342 if (ptid_equal (ptid, minus_one_ptid)) 00343 ptid = thread_to_gdb_id (current_inferior); 00344 00345 regcache_invalidate (); 00346 00347 errno = 0; 00348 lynx_ptrace (request, ptid, 1, signal, 0); 00349 if (errno) 00350 perror_with_name ("ptrace"); 00351 } 00352 00353 /* Resume the execution of the given PTID. */ 00354 00355 static void 00356 lynx_continue (ptid_t ptid) 00357 { 00358 struct thread_resume resume_info; 00359 00360 resume_info.thread = ptid; 00361 resume_info.kind = resume_continue; 00362 resume_info.sig = 0; 00363 00364 lynx_resume (&resume_info, 1); 00365 } 00366 00367 /* A wrapper around waitpid that handles the various idiosyncrasies 00368 of LynxOS' waitpid. */ 00369 00370 static int 00371 lynx_waitpid (int pid, int *stat_loc) 00372 { 00373 int ret = 0; 00374 00375 while (1) 00376 { 00377 ret = waitpid (pid, stat_loc, WNOHANG); 00378 if (ret < 0) 00379 { 00380 /* An ECHILD error is not indicative of a real problem. 00381 It happens for instance while waiting for the inferior 00382 to stop after attaching to it. */ 00383 if (errno != ECHILD) 00384 perror_with_name ("waitpid (WNOHANG)"); 00385 } 00386 if (ret > 0) 00387 break; 00388 /* No event with WNOHANG. See if there is one with WUNTRACED. */ 00389 ret = waitpid (pid, stat_loc, WNOHANG | WUNTRACED); 00390 if (ret < 0) 00391 { 00392 /* An ECHILD error is not indicative of a real problem. 00393 It happens for instance while waiting for the inferior 00394 to stop after attaching to it. */ 00395 if (errno != ECHILD) 00396 perror_with_name ("waitpid (WNOHANG|WUNTRACED)"); 00397 } 00398 if (ret > 0) 00399 break; 00400 usleep (1000); 00401 } 00402 return ret; 00403 } 00404 00405 /* Implement the wait target_ops method. */ 00406 00407 static ptid_t 00408 lynx_wait_1 (ptid_t ptid, struct target_waitstatus *status, int options) 00409 { 00410 int pid; 00411 int ret; 00412 int wstat; 00413 ptid_t new_ptid; 00414 00415 if (ptid_equal (ptid, minus_one_ptid)) 00416 pid = lynx_ptid_get_pid (thread_to_gdb_id (current_inferior)); 00417 else 00418 pid = BUILDPID (lynx_ptid_get_pid (ptid), lynx_ptid_get_tid (ptid)); 00419 00420 retry: 00421 00422 ret = lynx_waitpid (pid, &wstat); 00423 new_ptid = lynx_ptid_build (ret, ((union wait *) &wstat)->w_tid); 00424 find_process_pid (ret)->private->last_wait_event_ptid = new_ptid; 00425 00426 /* If this is a new thread, then add it now. The reason why we do 00427 this here instead of when handling new-thread events is because 00428 we need to add the thread associated to the "main" thread - even 00429 for non-threaded applications where the new-thread events are not 00430 generated. */ 00431 if (!find_thread_ptid (new_ptid)) 00432 { 00433 lynx_debug ("New thread: (pid = %d, tid = %d)", 00434 lynx_ptid_get_pid (new_ptid), lynx_ptid_get_tid (new_ptid)); 00435 add_thread (new_ptid, NULL); 00436 } 00437 00438 if (WIFSTOPPED (wstat)) 00439 { 00440 status->kind = TARGET_WAITKIND_STOPPED; 00441 status->value.integer = gdb_signal_from_host (WSTOPSIG (wstat)); 00442 lynx_debug ("process stopped with signal: %d", 00443 status->value.integer); 00444 } 00445 else if (WIFEXITED (wstat)) 00446 { 00447 status->kind = TARGET_WAITKIND_EXITED; 00448 status->value.integer = WEXITSTATUS (wstat); 00449 lynx_debug ("process exited with code: %d", status->value.integer); 00450 } 00451 else if (WIFSIGNALED (wstat)) 00452 { 00453 status->kind = TARGET_WAITKIND_SIGNALLED; 00454 status->value.integer = gdb_signal_from_host (WTERMSIG (wstat)); 00455 lynx_debug ("process terminated with code: %d", 00456 status->value.integer); 00457 } 00458 else 00459 { 00460 /* Not sure what happened if we get here, or whether we can 00461 in fact get here. But if we do, handle the event the best 00462 we can. */ 00463 status->kind = TARGET_WAITKIND_STOPPED; 00464 status->value.integer = gdb_signal_from_host (0); 00465 lynx_debug ("unknown event ????"); 00466 } 00467 00468 /* SIGTRAP events are generated for situations other than single-step/ 00469 breakpoint events (Eg. new-thread events). Handle those other types 00470 of events, and resume the execution if necessary. */ 00471 if (status->kind == TARGET_WAITKIND_STOPPED 00472 && status->value.integer == GDB_SIGNAL_TRAP) 00473 { 00474 const int realsig = lynx_ptrace (PTRACE_GETTRACESIG, new_ptid, 0, 0, 0); 00475 00476 lynx_debug ("(realsig = %d)", realsig); 00477 switch (realsig) 00478 { 00479 case SIGNEWTHREAD: 00480 /* We just added the new thread above. No need to do anything 00481 further. Just resume the execution again. */ 00482 lynx_continue (new_ptid); 00483 goto retry; 00484 00485 case SIGTHREADEXIT: 00486 remove_thread (find_thread_ptid (new_ptid)); 00487 lynx_continue (new_ptid); 00488 goto retry; 00489 } 00490 } 00491 00492 return new_ptid; 00493 } 00494 00495 /* A wrapper around lynx_wait_1 that also prints debug traces when 00496 such debug traces have been activated. */ 00497 00498 static ptid_t 00499 lynx_wait (ptid_t ptid, struct target_waitstatus *status, int options) 00500 { 00501 ptid_t new_ptid; 00502 00503 lynx_debug ("lynx_wait (pid = %d, tid = %ld)", 00504 lynx_ptid_get_pid (ptid), lynx_ptid_get_tid (ptid)); 00505 new_ptid = lynx_wait_1 (ptid, status, options); 00506 lynx_debug (" -> (pid=%d, tid=%ld, status->kind = %d)", 00507 lynx_ptid_get_pid (new_ptid), lynx_ptid_get_tid (new_ptid), 00508 status->kind); 00509 return new_ptid; 00510 } 00511 00512 /* Implement the kill target_ops method. */ 00513 00514 static int 00515 lynx_kill (int pid) 00516 { 00517 ptid_t ptid = lynx_ptid_build (pid, 0); 00518 struct target_waitstatus status; 00519 struct process_info *process; 00520 00521 process = find_process_pid (pid); 00522 if (process == NULL) 00523 return -1; 00524 00525 lynx_ptrace (PTRACE_KILL, ptid, 0, 0, 0); 00526 lynx_wait (ptid, &status, 0); 00527 the_target->mourn (process); 00528 return 0; 00529 } 00530 00531 /* Implement the detach target_ops method. */ 00532 00533 static int 00534 lynx_detach (int pid) 00535 { 00536 ptid_t ptid = lynx_ptid_build (pid, 0); 00537 struct process_info *process; 00538 00539 process = find_process_pid (pid); 00540 if (process == NULL) 00541 return -1; 00542 00543 lynx_ptrace (PTRACE_DETACH, ptid, 0, 0, 0); 00544 the_target->mourn (process); 00545 return 0; 00546 } 00547 00548 /* Implement the mourn target_ops method. */ 00549 00550 static void 00551 lynx_mourn (struct process_info *proc) 00552 { 00553 /* Free our private data. */ 00554 free (proc->private); 00555 proc->private = NULL; 00556 00557 clear_inferiors (); 00558 } 00559 00560 /* Implement the join target_ops method. */ 00561 00562 static void 00563 lynx_join (int pid) 00564 { 00565 /* The PTRACE_DETACH is sufficient to detach from the process. 00566 So no need to do anything extra. */ 00567 } 00568 00569 /* Implement the thread_alive target_ops method. */ 00570 00571 static int 00572 lynx_thread_alive (ptid_t ptid) 00573 { 00574 /* The list of threads is updated at the end of each wait, so it 00575 should be up to date. No need to re-fetch it. */ 00576 return (find_thread_ptid (ptid) != NULL); 00577 } 00578 00579 /* Implement the fetch_registers target_ops method. */ 00580 00581 static void 00582 lynx_fetch_registers (struct regcache *regcache, int regno) 00583 { 00584 struct lynx_regset_info *regset = lynx_target_regsets; 00585 ptid_t inferior_ptid = thread_to_gdb_id (current_inferior); 00586 00587 lynx_debug ("lynx_fetch_registers (regno = %d)", regno); 00588 00589 while (regset->size >= 0) 00590 { 00591 char *buf; 00592 int res; 00593 00594 buf = xmalloc (regset->size); 00595 res = lynx_ptrace (regset->get_request, inferior_ptid, (int) buf, 0, 0); 00596 if (res < 0) 00597 perror ("ptrace"); 00598 regset->store_function (regcache, buf); 00599 free (buf); 00600 regset++; 00601 } 00602 } 00603 00604 /* Implement the store_registers target_ops method. */ 00605 00606 static void 00607 lynx_store_registers (struct regcache *regcache, int regno) 00608 { 00609 struct lynx_regset_info *regset = lynx_target_regsets; 00610 ptid_t inferior_ptid = thread_to_gdb_id (current_inferior); 00611 00612 lynx_debug ("lynx_store_registers (regno = %d)", regno); 00613 00614 while (regset->size >= 0) 00615 { 00616 char *buf; 00617 int res; 00618 00619 buf = xmalloc (regset->size); 00620 res = lynx_ptrace (regset->get_request, inferior_ptid, (int) buf, 0, 0); 00621 if (res == 0) 00622 { 00623 /* Then overlay our cached registers on that. */ 00624 regset->fill_function (regcache, buf); 00625 /* Only now do we write the register set. */ 00626 res = lynx_ptrace (regset->set_request, inferior_ptid, (int) buf, 00627 0, 0); 00628 } 00629 if (res < 0) 00630 perror ("ptrace"); 00631 free (buf); 00632 regset++; 00633 } 00634 } 00635 00636 /* Implement the read_memory target_ops method. */ 00637 00638 static int 00639 lynx_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len) 00640 { 00641 /* On LynxOS, memory reads needs to be performed in chunks the size 00642 of int types, and they should also be aligned accordingly. */ 00643 int buf; 00644 const int xfer_size = sizeof (buf); 00645 CORE_ADDR addr = memaddr & -(CORE_ADDR) xfer_size; 00646 ptid_t inferior_ptid = thread_to_gdb_id (current_inferior); 00647 00648 while (addr < memaddr + len) 00649 { 00650 int skip = 0; 00651 int truncate = 0; 00652 00653 errno = 0; 00654 if (addr < memaddr) 00655 skip = memaddr - addr; 00656 if (addr + xfer_size > memaddr + len) 00657 truncate = addr + xfer_size - memaddr - len; 00658 buf = lynx_ptrace (PTRACE_PEEKTEXT, inferior_ptid, addr, 0, 0); 00659 if (errno) 00660 return errno; 00661 memcpy (myaddr + (addr - memaddr) + skip, (gdb_byte *) &buf + skip, 00662 xfer_size - skip - truncate); 00663 addr += xfer_size; 00664 } 00665 00666 return 0; 00667 } 00668 00669 /* Implement the write_memory target_ops method. */ 00670 00671 static int 00672 lynx_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len) 00673 { 00674 /* On LynxOS, memory writes needs to be performed in chunks the size 00675 of int types, and they should also be aligned accordingly. */ 00676 int buf; 00677 const int xfer_size = sizeof (buf); 00678 CORE_ADDR addr = memaddr & -(CORE_ADDR) xfer_size; 00679 ptid_t inferior_ptid = thread_to_gdb_id (current_inferior); 00680 00681 while (addr < memaddr + len) 00682 { 00683 int skip = 0; 00684 int truncate = 0; 00685 00686 if (addr < memaddr) 00687 skip = memaddr - addr; 00688 if (addr + xfer_size > memaddr + len) 00689 truncate = addr + xfer_size - memaddr - len; 00690 if (skip > 0 || truncate > 0) 00691 /* We need to read the memory at this address in order to preserve 00692 the data that we are not overwriting. */ 00693 lynx_read_memory (addr, (unsigned char *) &buf, xfer_size); 00694 if (errno) 00695 return errno; 00696 memcpy ((gdb_byte *) &buf + skip, myaddr + (addr - memaddr) + skip, 00697 xfer_size - skip - truncate); 00698 errno = 0; 00699 lynx_ptrace (PTRACE_POKETEXT, inferior_ptid, addr, buf, 0); 00700 if (errno) 00701 return errno; 00702 addr += xfer_size; 00703 } 00704 00705 return 0; 00706 } 00707 00708 /* Implement the kill_request target_ops method. */ 00709 00710 static void 00711 lynx_request_interrupt (void) 00712 { 00713 ptid_t inferior_ptid = thread_to_gdb_id (current_inferior); 00714 00715 kill (lynx_ptid_get_pid (inferior_ptid), SIGINT); 00716 } 00717 00718 /* The LynxOS target_ops vector. */ 00719 00720 static struct target_ops lynx_target_ops = { 00721 lynx_create_inferior, 00722 lynx_attach, 00723 lynx_kill, 00724 lynx_detach, 00725 lynx_mourn, 00726 lynx_join, 00727 lynx_thread_alive, 00728 lynx_resume, 00729 lynx_wait, 00730 lynx_fetch_registers, 00731 lynx_store_registers, 00732 NULL, /* prepare_to_access_memory */ 00733 NULL, /* done_accessing_memory */ 00734 lynx_read_memory, 00735 lynx_write_memory, 00736 NULL, /* look_up_symbols */ 00737 lynx_request_interrupt, 00738 NULL, /* read_auxv */ 00739 NULL, /* insert_point */ 00740 NULL, /* remove_point */ 00741 NULL, /* stopped_by_watchpoint */ 00742 NULL, /* stopped_data_address */ 00743 NULL, /* read_offsets */ 00744 NULL, /* get_tls_address */ 00745 NULL, /* qxfer_spu */ 00746 NULL, /* hostio_last_error */ 00747 NULL, /* qxfer_osdata */ 00748 NULL, /* qxfer_siginfo */ 00749 NULL, /* supports_non_stop */ 00750 NULL, /* async */ 00751 NULL, /* start_non_stop */ 00752 NULL, /* supports_multi_process */ 00753 NULL, /* handle_monitor_command */ 00754 }; 00755 00756 void 00757 initialize_low (void) 00758 { 00759 set_target_ops (&lynx_target_ops); 00760 the_low_target.arch_setup (); 00761 } 00762