GDBserver
/home/stan/gdb/src/gdb/gdbserver/lynx-low.c
Go to the documentation of this file.
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 
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Defines