123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754 |
- /* $Header$ */
- /* Running a process and communication */
- #include <signal.h>
- #include <stdio.h>
- #include <assert.h>
- #include <alloc.h>
- #include <errno.h>
- #include "ops.h"
- #include "message.h"
- #include "position.h"
- #include "tree.h"
- #include "file.h"
- #include "symbol.h"
- #include "idf.h"
- #include "scope.h"
- #include "type.h"
- #include "expr.h"
- #include "misc.h"
- #define MAXARG 128
- extern char *strncpy();
- extern char *malloc();
- extern struct idf *str2idf();
- extern char *AObj;
- extern FILE *db_out;
- extern int debug;
- extern char *progname;
- extern int child_interrupted;
- extern int interrupted;
- extern t_lineno currline;
- static int child_pid; /* process id of child */
- static int to_child, from_child; /* file descriptors for communication */
- static int child_status;
- static int restoring;
- static int fild1[2], fild2[2]; /* pipe file descriptors */
- int disable_intr = 1;
- int db_ss;
- int stack_offset;
- void signal_child();
- static void catch_sigpipe();
- static int stopped();
- static int uputm(), ugetm();
- static t_addr curr_stop;
- p_tree run_command;
- static void
- ITOBUF(p, l, sz)
- register char *p;
- long l;
- int sz;
- {
- register int i;
- p +=sz;
- for (i = sz; i > 0; i--) {
- *--p = l;
- l >>= 8;
- }
- }
- static long
- BUFTOI(p, sz)
- register char *p;
- int sz;
- {
- register long l = 0;
- register int i;
- for (i = sz; i>0; i--) {
- l = (l << 8) | (*p++ & 0377);
- }
- return l;
- }
- void
- init_run()
- {
- /* take file descriptors so that listing cannot take them */
- int i;
- for (i = 3; i <= 6; i++) close(i);
- if (pipe(fild1) < 0 ||
- pipe(fild2) < 0 ||
- fild1[0] != 3 ||
- fild2[1] != 6) {
- fatal("something wrong with file descriptors");
- }
- to_child = fild1[1];
- from_child = fild2[0];
- child_pid = 0;
- if (currfile) CurrentScope = currfile->sy_file->f_scope;
- currline = 0;
- }
- extern int errno;
- start_child(p)
- p_tree p;
- {
- /* start up the process to be debugged and set up communication */
- char *argp[MAXARG]; /* argument list */
- register p_tree pt = p->t_args[0], pt1 = 0;
- unsigned int nargs = 1; /* #args */
- char *in_redirect = 0; /* standard input redirected */
- char *out_redirect = 0; /* standard output redirected */
- signal_child(SIGKILL); /* like families in China, this debugger is only
- allowed one child
- */
- if (p != run_command) {
- freenode(run_command);
- run_command = p;
- }
- /* first check arguments and redirections and build argument list */
- while (pt) {
- switch(pt->t_oper) {
- case OP_LINK:
- pt1 = pt->t_args[1];
- pt = pt->t_args[0];
- continue;
- case OP_NAME:
- if (nargs < (MAXARG-1)) {
- argp[nargs++] = pt->t_str;
- }
- else {
- error("too many arguments");
- return;
- }
- break;
- case OP_INPUT:
- if (in_redirect) {
- error("input redirected twice?");
- return;
- }
- in_redirect = pt->t_str;
- break;
- case OP_OUTPUT:
- if (out_redirect) {
- error("output redirected twice?");
- return;
- }
- out_redirect = pt->t_str;
- break;
- }
- if (pt != pt1) pt = pt1;
- else break;
- }
- argp[0] = AObj;
- argp[nargs] = 0;
- /* create child process */
- child_pid = fork();
- if (child_pid < 0) {
- error("could not create child");
- return;
- }
- if (child_pid == 0) {
- /* this is the child process */
- close(fild1[1]);
- close(fild2[0]);
- signal(SIGINT, SIG_IGN);
- /* I/O redirection */
- if (in_redirect) {
- int fd;
- close(0);
- if ((fd = open(in_redirect, 0)) < 0 ||
- (fd != 0 && dup2(fd, 0) < 0)) {
- perror(progname);
- exit(1);
- }
- if (fd != 0) {
- close(fd);
- }
- }
- if (out_redirect) {
- int fd;
- close(1);
- if ((fd = creat(out_redirect, 0666)) < 0 ||
- (fd != 1 && dup2(fd, 1) < 0)) {
- perror(progname);
- exit(1);
- }
- if (fd != 1) {
- close(fd);
- }
- }
- /* and run process to be debugged */
- execv(AObj, argp);
- error("could not exec %s", AObj);
- exit(1);
- }
- /* close fild1[0] and fild2[1]; but we want those file descriptors occupied,
- so we re-occupy them.
- */
- close(fild1[0]);
- close(fild2[1]);
- pipe(fild1); /* to occupy file descriptors */
- signal(SIGPIPE, catch_sigpipe);
- {
- struct message_hdr m;
- if (! ugetm(&m)) {
- error("child not responding");
- init_run();
- return;
- }
- curr_stop = BUFTOI(m.m_buf+1, PS);
- CurrentScope = get_scope_from_addr(curr_stop);
- }
- perform_items();
- if (! restoring) {
- int stop_reason = item_addr_actions(curr_stop, 1, 1);
- if (! stop_reason) (void) send_cont(1);
- else (void) stopped("stopped", curr_stop, stop_reason);
- }
- }
- void
- signal_child(sig)
- {
- if (child_pid) {
- kill(child_pid, sig);
- if (sig == SIGKILL) {
- wait(&child_status);
- init_run();
- }
- }
- }
- static void
- catch_sigpipe()
- {
- child_pid = 0;
- }
- extern int errno;
- static int
- do_read(f, p, c)
- char *p;
- {
- int i = read(f, p, c);
- while (i < 0 && errno == EINTR) i = read(f, p, c);
- return i;
- }
- static int
- ureceive(p, c)
- char *p;
- long c;
- {
- int i;
- char buf[0x1000];
- if (! child_pid) {
- error("no process");
- return 0;
- }
- if (! p) p = buf;
- while (c >= 0x1000) {
- i = do_read(from_child, p, 0x1000);
- if (i <= 0) {
- if (i == 0) {
- child_pid = 0;
- }
- else error("read failed");
- return 0;
- }
- if (p != buf) p += i;
- c -= i;
- }
- while (c > 0) {
- i = do_read(from_child, p, (int)c);
- if (i <= 0) {
- if (i == 0) {
- child_pid = 0;
- }
- else error("read failed");
- return 0;
- }
- p += i;
- c -= i;
- }
- return 1;
- }
- static int
- usend(p, c)
- char *p;
- long c;
- {
- int i;
- if (! child_pid) {
- error("no process");
- return 0;
- }
- while (c >= 0x1000) {
- i = write(to_child, p, 0x1000);
- if (i < 0) {
- if (child_pid) error("write failed");
- return 0;
- }
- p += i;
- c -= i;
- }
- while (c > 0) {
- i = write(to_child, p, (int)c);
- if (i < 0) {
- if (child_pid) error("write failed");
- return 0;
- }
- p += i;
- c -= i;
- }
- return 1;
- }
- static int
- ugetm(message)
- struct message_hdr *message;
- {
- if (! ureceive((char *) message, (long) sizeof(struct message_hdr))) {
- return 0;
- }
- if (debug) printf("Got %d\n", message->m_type);
- return 1;
- }
- static int
- uputm(message)
- struct message_hdr *message;
- {
- if (! usend((char *) message, (long) sizeof(struct message_hdr))) {
- return 0;
- }
- if (debug) printf("Sent %d\n", message->m_type);
- return 1;
- }
- static struct message_hdr answer;
- static int single_stepping;
- static int
- stopped(s, a, stop_reason)
- char *s; /* stop message */
- t_addr a; /* address where stopped */
- int stop_reason; /* status entry causing the stop */
- {
- p_position pos;
- if (s && a) {
- fprintf(db_out, "%s ", s);
- pos = print_position(a, 1);
- if (stop_reason) {
- fprintf(db_out, " (status entry %d)", stop_reason);
- }
- fputs("\n", db_out);
- list_position(pos);
- handle_displays();
- }
- curr_stop = a;
- CurrentScope = get_scope_from_addr(a);
- return 1;
- }
- static int
- could_send(m, stop_message)
- struct message_hdr *m;
- {
- int type;
- t_addr a;
- static int level = 0;
- int child_dead = 0;
- int stop_reason;
- level++;
- for (;;) {
- stop_reason = 0;
- if (! child_pid) {
- error("no process");
- return 0;
- }
- if (m->m_type & M_DB_RUN) {
- disable_intr = 0;
- stack_offset = 0;
- }
- if (!child_interrupted && (! uputm(m) || ! ugetm(&answer))) {
- child_dead = 1;
- }
- disable_intr = 1;
- if ((interrupted || child_interrupted) && ! child_dead) {
- while (child_interrupted && answer.m_type != M_INTR) {
- if (! ugetm(&answer)) {
- child_dead = 1;
- break;
- }
- }
- if (interrupted && ! child_dead) {
- level--;
- if (! level) {
- child_interrupted = 0;
- interrupted = 0;
- return stopped("interrupted", (t_addr) BUFTOI(answer.m_buf+1, PS), 0);
- }
- return 1;
- }
- }
- if (child_dead) {
- wait(&child_status);
- if (child_status & 0177) {
- fprintf(db_out,
- "child died with signal %d\n",
- child_status & 0177);
- }
- else {
- fprintf(db_out,
- "child terminated, exit status %d\n",
- child_status >> 8);
- }
- init_run();
- level--;
- return 1;
- }
- a = BUFTOI(answer.m_buf+1, PS);
- type = answer.m_type & 0377;
- if (type == M_END_SS) type = 0;
- else if (type == M_OK || type == M_DB_SS) type = 1;
- else type = 2;
- if (m->m_type & M_DB_RUN) {
- /* run command */
- CurrentScope = get_scope_from_addr((t_addr) a);
- if (!(stop_reason = item_addr_actions(a, type, stop_message))
- && (type == 1)) {
- /* no explicit breakpoints at this position.
- Also, child did not stop because of
- SETSS or SETSSF, otherwise we would
- have gotten END_SS.
- So, continue.
- */
- if ((m->m_type & 0177) != M_CONT) {
- m->m_type = M_CONT | (m->m_type & M_DB_SS);
- }
- continue;
- }
- if (type != 0 && single_stepping) {
- m->m_type = M_CLRSS;
- if (! uputm(m) || ! ugetm(&answer)) return 0;
- }
- single_stepping = 0;
- }
- level--;
- if (stop_message) {
- return stopped("stopped", a, stop_reason);
- }
- return 1;
- }
- /*NOTREACHED*/
- }
- static int
- getbytes(size, from, to, kind, errmess)
- long size;
- t_addr from;
- char *to;
- int kind;
- int errmess;
- {
- struct message_hdr m;
- m.m_type = kind;
- ITOBUF(m.m_buf+1, size, LS);
- ITOBUF(m.m_buf+LS+1, (long)from, PS);
- if (! could_send(&m, 0)) {
- return 0;
- }
- switch(answer.m_type) {
- case M_FAIL:
- if (errmess) error("could not get value");
- return 0;
- case M_INTR:
- if (errmess) error("interrupted");
- return 0;
- case M_DATA:
- return ureceive(to, BUFTOI(answer.m_buf+1, LS));
- default:
- assert(0);
- }
- /*NOTREACHED*/
- }
- int
- get_bytes(size, from, to)
- long size;
- t_addr from;
- char *to;
- {
- return getbytes(size, from, to, M_GETBYTES, 1);
- }
- int
- get_string(size, from, to)
- long size;
- t_addr from;
- char *to;
- {
- int retval = getbytes(size, from, to, M_GETSTR, 0);
- to[(int)BUFTOI(answer.m_buf+1, LS)] = 0;
- return retval;
- }
- void
- set_bytes(size, from, to)
- long size;
- char *from;
- t_addr to;
- {
- struct message_hdr m;
- m.m_type = M_SETBYTES;
- ITOBUF(m.m_buf+1, size, LS);
- ITOBUF(m.m_buf+LS+1, (long) to, PS);
- if (! uputm(&m) || ! usend(from, size) || ! ugetm(&m)) {
- return;
- }
- switch(answer.m_type) {
- case M_FAIL:
- error("could not handle this SET request");
- break;
- case M_INTR:
- error("interrupted");
- break;
- case M_OK:
- break;
- default:
- assert(0);
- }
- }
- t_addr
- get_dump(globbuf, stackbuf)
- char **globbuf, **stackbuf;
- {
- struct message_hdr m;
- struct message_hdr *globm, *stackm;
- long sz;
- m.m_type = M_DUMP;
- if (! could_send(&m, 0)) {
- return 0;
- }
- switch(answer.m_type) {
- case M_FAIL:
- error("request for DUMP failed");
- return 0;
- case M_INTR:
- error("interrupted");
- return 0;
- case M_DGLOB:
- break;
- default:
- assert(0);
- }
- sz = BUFTOI(answer.m_buf+1, LS);
- *globbuf = malloc((unsigned) (sz+sizeof(struct message_hdr)));
- if (! *globbuf
- || ! ureceive(*globbuf+sizeof(struct message_hdr), sz)
- || ! ugetm(&m)) {
- if (*globbuf) free(*globbuf);
- else error("could not allocate enougn memory");
- return 0;
- }
- globm = (struct message_hdr *) *globbuf;
- *globm = answer;
- assert(m.m_type == M_DSTACK);
- sz = BUFTOI(m.m_buf+1, LS);
- *stackbuf = malloc((unsigned) sz+sizeof(struct message_hdr));
- if (! *stackbuf || ! ureceive(*stackbuf+sizeof(struct message_hdr), sz)) {
- free(*globbuf);
- if (*stackbuf) free(*stackbuf);
- else error("could not allocate enougn memory");
- return 0;
- }
- stackm = (struct message_hdr *) *stackbuf;
- *stackm = m;
- ITOBUF(globm->m_buf+SP_OFF, BUFTOI(stackm->m_buf+SP_OFF, PS), PS);
- return BUFTOI(globm->m_buf+PC_OFF, PS);
- }
- int
- put_dump(globbuf, stackbuf)
- char *globbuf, *stackbuf;
- {
- struct message_hdr m;
- struct message_hdr *globm = (struct message_hdr *) globbuf,
- *stackm = (struct message_hdr *) stackbuf;
- stackbuf += sizeof(struct message_hdr);
- globbuf += sizeof(struct message_hdr);
- if (! child_pid) {
- restoring = 1;
- start_child(run_command);
- restoring = 0;
- }
- return uputm(globm)
- && usend(globbuf, BUFTOI(globm->m_buf+1, LS))
- && uputm(stackm)
- && usend(stackbuf, BUFTOI(stackm->m_buf+1, LS))
- && ugetm(&m)
- && stopped("restored", BUFTOI(m.m_buf+1, PS), 0);
- }
- t_addr *
- get_EM_regs(level)
- int level;
- {
- struct message_hdr m;
- static t_addr buf[5];
- register t_addr *to = &buf[0];
- m.m_type = M_GETEMREGS;
- ITOBUF(m.m_buf+1, (long) level, LS);
- if (! could_send(&m, 0)) {
- return 0;
- }
- switch(answer.m_type) {
- case M_FAIL:
- error("request for registers failed");
- return 0;
- case M_INTR:
- error("interrupted");
- return 0;
- case M_GETEMREGS:
- break;
- default:
- assert(0);
- }
- *to++ = (t_addr) BUFTOI(answer.m_buf+LB_OFF, PS);
- *to++ = (t_addr) BUFTOI(answer.m_buf+AB_OFF, PS);
- *to++ = (t_addr) BUFTOI(answer.m_buf+PC_OFF, PS);
- *to++ = (t_addr) BUFTOI(answer.m_buf+HP_OFF, PS);
- *to++ = (t_addr) BUFTOI(answer.m_buf+PC_OFF, PS);
- return buf;
- }
- int
- set_pc(PC)
- t_addr PC;
- {
- struct message_hdr m;
- m.m_type = M_SETEMREGS;
- ITOBUF(m.m_buf+PC_OFF, (long)PC, PS);
- if (! could_send(&m, 0)) return 0;
- switch(answer.m_type) {
- case M_FAIL:
- error("could not set PC to %lx", (long) PC);
- return 0;
- case M_INTR:
- error("interrupted");
- return 0;
- case M_OK:
- return 1;
- default:
- assert(0);
- }
- /*NOTREACHED*/
- }
- int
- send_cont(stop_message)
- int stop_message;
- {
- struct message_hdr m;
- m.m_type = (M_CONT | (db_ss ? M_DB_SS : 0));
- return could_send(&m, stop_message) && child_pid;
- }
- int
- singlestep(type, count)
- int type;
- long count;
- {
- struct message_hdr m;
- m.m_type = (type ? M_SETSSF : M_SETSS) | (db_ss ? M_DB_SS : 0);
- ITOBUF(m.m_buf+1, count, LS);
- single_stepping = 1;
- if (could_send(&m, 1) && child_pid) return 1;
- single_stepping = 0;
- return 0;
- }
- int
- set_or_clear_breakpoint(a, type)
- t_addr a;
- int type;
- {
- struct message_hdr m;
- m.m_type = type ? M_SETBP : M_CLRBP;
- ITOBUF(m.m_buf+1, (long) a, PS);
- if (debug) printf("%s breakpoint at 0x%lx\n", type ? "setting" : "clearing", (long) a);
- if (child_pid && ! could_send(&m, 0)) {
- }
- return 1;
- }
- int
- set_or_clear_trace(start, end, type)
- t_addr start, end;
- int type;
- {
- struct message_hdr m;
- m.m_type = type ? M_SETTRACE : M_CLRTRACE;
- ITOBUF(m.m_buf+1, (long)start, PS);
- ITOBUF(m.m_buf+PS+1, (long)end, PS);
- if (debug) printf("%s trace at [0x%lx,0x%lx]\n", type ? "setting" : "clearing", (long) start, (long) end);
- if (child_pid && ! could_send(&m, 0)) {
- return 0;
- }
- return 1;
- }
|