From e8007cc0ef5e64c57d63ae87794de3b4d72a5466 Mon Sep 17 00:00:00 2001 From: Oliver Stieber Date: Thu, 10 Feb 2005 21:18:12 +0000 Subject: [PATCH] Added vCont support. --- programs/winedbg/gdbproxy.c | 218 +++++++++++++++++++++++++++++++++++- 1 file changed, 215 insertions(+), 3 deletions(-) diff --git a/programs/winedbg/gdbproxy.c b/programs/winedbg/gdbproxy.c index 018235addb9..1c5d7f62980 100644 --- a/programs/winedbg/gdbproxy.c +++ b/programs/winedbg/gdbproxy.c @@ -123,6 +123,15 @@ static inline unsigned char hex_to0(int x) return "0123456789abcdef"[x]; } +static int hex_to_int(const char* src, size_t len){ + unsigned int returnval = 0; + while (len--){ + returnval=hex_from0(src[0]); + if(len) returnval<<=4; + } + return returnval; +} + static void hex_from(void* dst, const char* src, size_t len) { unsigned char *p = dst; @@ -572,7 +581,28 @@ static void resume_debuggee(struct gdb_context* gdbctx, unsigned long cont) dbg_curr_thread->tid, cont); } else if (gdbctx->trace & GDBPXY_TRC_WIN32_ERROR) - fprintf(stderr, "Cannot find last thread (%lu)\n", dbg_curr_thread->tid); + fprintf(stderr, "Cannot find last thread\n"); +} + + +static void resume_debuggee_thread(struct gdb_context* gdbctx, unsigned long cont, unsigned int threadid) +{ + + if (dbg_curr_thread) + { + if(dbg_curr_thread->tid == threadid){ + /* Windows debug and GDB don't seem to work well here, windows only likes ContinueDebugEvent being used on the reporter of the event */ + if (!SetThreadContext(dbg_curr_thread->handle, &gdbctx->context)) + if (gdbctx->trace & GDBPXY_TRC_WIN32_ERROR) + fprintf(stderr, "Cannot set context on thread %lu\n", dbg_curr_thread->tid); + if (!ContinueDebugEvent(gdbctx->process->pid, dbg_curr_thread->tid, cont)) + if (gdbctx->trace & GDBPXY_TRC_WIN32_ERROR) + fprintf(stderr, "Cannot continue on %lu (%lu)\n", + dbg_curr_thread->tid, cont); + } + } + else if (gdbctx->trace & GDBPXY_TRC_WIN32_ERROR) + fprintf(stderr, "Cannot find last thread\n"); } static void wait_for_debuggee(struct gdb_context* gdbctx) @@ -866,6 +896,185 @@ static enum packet_return packet_continue(struct gdb_context* gdbctx) return packet_reply_status(gdbctx); } +static enum packet_return packet_verbose(struct gdb_context* gdbctx) +{ + int i; + int defaultAction = -1; /* magic non action */ + unsigned char sig; + int actions =0; + int actionIndex[20]; /* allow for upto 20 actions */ + int threadIndex[20]; + int threadCount = 0; + unsigned int threadIDs[100]; /* TODO: Should make this dynamic */ + unsigned int threadID = 0; + struct dbg_thread* thd; + + /* basic check */ + assert(gdbctx->in_packet_len >= 4); + + /* OK we have vCont followed by.. + * ? for query + * c for packet_continue + * Csig for packet_continue_signal + * s for step + * Ssig for step signal + * and then an optional thread ID at the end.. + * *******************************************/ + + fprintf(stderr, "trying to process a verbose packet\n"); + /* now check that we've got Cont */ + assert(strncmp(gdbctx->in_packet, "Cont", 4) == 0); + + /* Query */ + if(gdbctx->in_packet[4] == '?'){ + /* + Reply: + `vCont[;action]...' + The vCont packet is supported. Each action is a supported command in the vCont packet. + `' + The vCont packet is not supported. (this didn't seem to be obayed!) + */ + packet_reply_open(gdbctx); + packet_reply_add(gdbctx, "vCont", 5); + /* add all the supported actions to the reply (all of them for now)*/ + packet_reply_add(gdbctx, ";c", 2); + packet_reply_add(gdbctx, ";C", 2); + packet_reply_add(gdbctx, ";s", 2); + packet_reply_add(gdbctx, ";S", 2); + packet_reply_close(gdbctx); + return packet_done; + } + + /* This may not be the 'fastest' code in the world. but it should be nice and easy to debug. + (as it's run when people are debugging break points I'm sure they won't notice the extra 100 cycles anyway) + now if only gdb talked XML.... */ +#if 0 /* handy for debugging */ + fprintf(stderr, "no, but can we find a default packet %.*s %d\n", gdbctx->in_packet_len, gdbctx->in_packet, gdbctx->in_packet_len); +#endif + + /* go through the packet and identify where all the actions start att */ + for(i = 4; i < gdbctx->in_packet_len - 1; i++){ + if(gdbctx->in_packet[i] == ';'){ + threadIndex[actions] = 0; + actionIndex[actions++] = i; + }else if(gdbctx->in_packet[i] == ':'){ + threadIndex[actions - 1] = i; + } + } + + /* now look up the default action */ + for(i = 0 ; i < actions; i++){ + if(threadIndex[i] == 0){ + if(defaultAction != -1){ + fprintf(stderr,"Too many default actions specified\n"); + return packet_error; + } + defaultAction = i; + } + } + + /* Now, I have this default action thing that needs to be applied to all non counted threads */ + + /* go through all the threads and stick there id's in the to be done list. */ + for (thd = gdbctx->process->threads; thd; thd = thd->next) + { + threadIDs[threadCount++] = thd->tid; + /* check to see if we have more threads than I counted on, and tell the user what to do + * (their running winedbg, so I'm sure they can fix the problem from the error message!) */ + if(threadCount == 100){ + fprintf(stderr, "Wow, that's a lot of threads, change threadIDs in wine/programms/winedgb/gdbproxy.c to be higher\n"); + break; + } + } + + /* Ok, now we have... actionIndex full of actions and we know what threads there are, so all + * that remains is to apply the actions to the threads and the default action to any threads + * left */ + if (dbg_curr_thread != gdbctx->exec_thread && gdbctx->exec_thread) + if (gdbctx->trace & GDBPXY_TRC_COMMAND_FIXME) + fprintf(stderr, "NIY: cont on %lu, while last thread is %lu\n", + gdbctx->exec_thread->tid, dbg_curr_thread->tid); + + /* deal with the threaded stuff first */ + for( i = 0; i < actions ; i++){ + + if(threadIndex[i] != 0){ + + int j, idLength = 0; + if(i < actions - 1){ + idLength = (actionIndex[i+1] - threadIndex[i]) - 1; + } else{ + idLength = (gdbctx->in_packet_len - threadIndex[i]) - 1; + } + + threadID = hex_to_int( gdbctx->in_packet + threadIndex[i] + 1 , idLength); + /* process the action */ + switch(gdbctx->in_packet[actionIndex[i] + 1]){ + case 's': /* step */ + be_cpu->single_step(&gdbctx->context, TRUE); + /* fall through*/ + case 'c': /* continue */ + resume_debuggee_thread(gdbctx, DBG_CONTINUE, threadID); + break; + case 'S': /* step Sig, */ + be_cpu->single_step(&gdbctx->context, TRUE); + /* fall through */ + case 'C': /* continue sig */ + hex_from(&sig, gdbctx->in_packet + actionIndex[i] + 2, 1); + /* cannot change signals on the fly */ + if (gdbctx->trace & GDBPXY_TRC_COMMAND) + fprintf(stderr, "sigs: %u %u\n", sig, gdbctx->last_sig); + if (sig != gdbctx->last_sig) + return packet_error; + resume_debuggee_thread(gdbctx, DBG_EXCEPTION_NOT_HANDLED, threadID); + break; + } + for(j = 0 ; j< threadCount; j++){ + if(threadIDs[j] == threadID){ + threadIDs[j] = 0; + break; + } + } + } + } /* for i=0 ; i< actions */ + + /* now we have manage the default action */ + if(defaultAction >=0){ + for(i = 0 ; i< threadCount; i++){ + /* check to see if we've already done something to the thread*/ + if(threadIDs[i] != 0){ + /* if not apply the default action*/ + threadID = threadIDs[i]; + /* process the action (yes this is almost identical to the one above!) */ + switch(gdbctx->in_packet[actionIndex[defaultAction] + 1]){ + case 's': /* step */ + be_cpu->single_step(&gdbctx->context, TRUE); + /* fall through */ + case 'c': /* continue */ + resume_debuggee_thread(gdbctx, DBG_CONTINUE, threadID); + break; + case 'S': + be_cpu->single_step(&gdbctx->context, TRUE); + /* fall through */ + case 'C': /* continue sig */ + hex_from(&sig, gdbctx->in_packet + actionIndex[defaultAction] + 2, 1); + /* cannot change signals on the fly */ + if (gdbctx->trace & GDBPXY_TRC_COMMAND) + fprintf(stderr, "sigs: %u %u\n", sig, gdbctx->last_sig); + if (sig != gdbctx->last_sig) + return packet_error; + resume_debuggee_thread(gdbctx, DBG_EXCEPTION_NOT_HANDLED, threadID); + break; + } + } + } + } /* if(defaultAction >=0) */ + + wait_for_debuggee(gdbctx); + be_cpu->single_step(&gdbctx->context, FALSE); + return packet_reply_status(gdbctx); +} + static enum packet_return packet_continue_signal(struct gdb_context* gdbctx) { unsigned char sig; @@ -1604,7 +1813,7 @@ struct packet_entry static struct packet_entry packet_entries[] = { -/* {'!', packet_extended}, */ + /*{'!', packet_extended}, */ {'?', packet_last_signal}, {'c', packet_continue}, {'C', packet_continue_signal}, @@ -1618,9 +1827,12 @@ static struct packet_entry packet_entries[] = /* {'p', packet_read_register}, doesn't seem needed */ {'P', packet_write_register}, {'q', packet_query}, - {'s', packet_step}, + /* {'Q', packet_set}, */ + /* {'R', packet,restart}, only in extended mode ! */ + {'s', packet_step}, /*{'S', packet_step_signal}, hard(er) to implement */ {'T', packet_thread_alive}, + {'v', packet_verbose}, {'z', packet_remove_breakpoint}, {'Z', packet_set_breakpoint}, };