/***************************************************************/ /* mgdb: midipix-specific bits for gdb */ /* Copyright (C) 2019 Z. Gilboa */ /* Released under GPLv2 and GPLv3; see COPYING.MGDB. */ /***************************************************************/ #include "defs.h" #include "osabi.h" #include "config.h" #include "target.h" #include "main.h" #include "utils.h" #include "inferior.h" #include "gdbcore.h" #include "gdbthread.h" #include "inf-child.h" #include "xml-support.h" #include "winnt-nat.h" #include "x86-nat.h" #include #include #include #include #include #include #include #include #define WINNT_OUTBUF_SIZE 65536 #define X86_DR_RTM_MASK (1 << 16) #define X86_EFLAGS_TRACE (1 << 8) #define winnt_error(msg) \ error("%s(): %s.",__FUNCTION__,msg) #define winnt_perror(msg,pid) \ error("%s(): %s (pid %d).",__FUNCTION__,msg,pid) #define WINNT_W32_EXCEPTION_MASK ((0xe0 << 24) | ('m' << 16) | ('s' << 8) | ('c' << 0)) #define WINNT_ZED_EXCEPTION_MASK ((0x2d << 24) | ('Z' << 16) | ('E' << 8) | ('D' << 0)) #define WINNT_GCC_EXCEPTION_MASK ((0x20 << 24) | ('G' << 16) | ('C' << 8) | ('C' << 0)) static size_t pcnt; static winnt_process * plist; static char * outbuf; static struct pe_driver_ctx * pe_dctx; static struct winnt_exception_filter winnt_exception_filters[] = { {WINNT_W32_EXCEPTION_MASK, WINNT_EXCEPTION_FIRST_CHANCE, 0}, {WINNT_ZED_EXCEPTION_MASK, WINNT_EXCEPTION_FIRST_CHANCE, 0}, {WINNT_GCC_EXCEPTION_MASK, WINNT_EXCEPTION_FIRST_CHANCE, 0}, {0, WINNT_EXCEPTION_FIRST_CHANCE, "sysfer.dll"}, {0, 0, 0}, }; static winnt_process * winnt_plist_expand (void) { struct winnt_process * pnew; struct winnt_process * pold; size_t idx; if (!(pnew = (struct winnt_process *)calloc(pcnt+32, sizeof(*pnew)))) return 0; memcpy( pnew,plist, pcnt*sizeof(*plist)); pold = plist; plist = pnew; pcnt += 32; free(pold); return pnew; } static int winnt_plist_add (pid_t pid, int pfd) { struct winnt_process * pdbg; struct winnt_process * pcap; for (pdbg=plist, pcap=&plist[pcnt]; pdbgpid) { pdbg->pid = pid; pdbg->pfd = pfd; return 0; } } return winnt_plist_expand() ? winnt_plist_add(pid,pfd) : -1; } static void winnt_free_modules(struct winnt_process * pidinfo) { struct __dbg_module_info * module; struct __dbg_module_info * modules_base; struct __dbg_module_info * modules_cap; if (!pidinfo->modules) return; modules_base = pidinfo->modules; modules_cap = &modules_base[pidinfo->nmodules]; for (module=modules_base; modulemodule_name) free(module->module_name); if (module->module_ctx) pe_free_unit_ctx((pe_unit_ctx *)module->module_ctx); } if (pidinfo->solibs) free(pidinfo->solibs); free(pidinfo->modules); pidinfo->modules = 0; pidinfo->nmodules = 0; pidinfo->solibs = 0; } static void winnt_free_threads(struct winnt_process * pidinfo) { struct winnt_thread * thread; struct winnt_thread * next; next = pidinfo->threads; for (thread=next; thread; thread=next) { next = thread->next; free(thread); } } static void winnt_plist_remove (pid_t pid) { struct winnt_process * pdbg; struct winnt_process * pcap; for (pdbg=plist, pcap=&plist[pcnt]; pdbgpid == pid) { close(pdbg->pfd); winnt_free_modules(pdbg); winnt_free_threads(pdbg); memset(pdbg,0,sizeof(*pdbg)); return; } } } static struct winnt_process * winnt_process_record(pid_t pid) { winnt_process * pdbg; winnt_process * pcap; if (!pid) return 0; for (pdbg=plist, pcap=&plist[pcnt]; pdbgpid == pid) return pdbg; return 0; } static ptid_t winnt_get_ada_task_ptid (struct target_ops * t, long lwp, long tid) { ptid_t ptid; (void)t; ptid.pid = inferior_ptid.pid; ptid.lwp = 0; ptid.tid = lwp; return ptid; } static char * winnt_pid_to_exec_file (struct target_ops * t, int pid) { ssize_t ret; struct winnt_process * pidinfo; if (!(pidinfo = winnt_process_record(pid))) winnt_perror("internal error: record not found",pid); ret = __dbg_info_get( pidinfo->pfd,0, __DBG_INFO_IMAGE_RPATH, outbuf,WINNT_OUTBUF_SIZE); if (ret < 0) ret = __dbg_info_get( pidinfo->pfd,0, __DBG_INFO_REPORTED_IMAGE_RPATH, outbuf,WINNT_OUTBUF_SIZE); if (ret < 0) outbuf[0] = 0; return outbuf; } static void winnt_get_modules(struct winnt_process * pidinfo) { void * addr; char * xmlstr; char * mark; char * text; struct pe_unit_ctx * uctx; struct pe_meta_sec_hdr * sechdr; struct __dbg_module_info * module; struct __dbg_module_info * modules; struct __dbg_module_info * modules_cap; ssize_t nbytes; size_t nmodules; size_t buflen; int secidx; winnt_free_modules(pidinfo); if (!(addr = calloc(2048,sizeof(*modules)))) return; nbytes = __dbg_info_get( pidinfo->pfd,0, __DBG_INFO_CACHED_MODULE_LIST, addr,2048*sizeof(*modules)); if (nbytes < 0) { free(addr); return; }; nmodules = nbytes / sizeof(*modules); modules = (struct __dbg_module_info *)calloc(nmodules,sizeof(*modules)); if (!modules) { free(addr); return; } memcpy(modules,addr,nmodules*sizeof(*modules)); free(addr); buflen = 64; module = modules; modules_cap = &modules[nmodules]; for (; modulepfd,module->module_key, __DBG_INFO_MODULE_RPATH, outbuf,WINNT_OUTBUF_SIZE); if (nbytes > 0) { module->module_name = strdup(outbuf); xmlstr = xml_escape_text(outbuf); if (xmlstr) { buflen += strlen(xmlstr) + 128; xfree(xmlstr); } pe_get_unit_ctx( pe_dctx, module->module_name, (pe_unit_ctx **)&module->module_ctx); } module++; } module = modules; pidinfo->modules = modules; pidinfo->nmodules = nmodules; if (!(pidinfo->solibs = (char *)calloc(1,buflen))) return; mark = pidinfo->solibs; mark += sprintf(mark,"\n"); for (; modulemodule_name) { if ((xmlstr = xml_escape_text(module->module_name))) { mark += sprintf(mark,"",xmlstr); xfree(xmlstr); } /* text */ if ((uctx = (pe_unit_ctx *)module->module_ctx)) { secidx = pe_get_named_section_index( uctx->meta,".text"); if (secidx >= 0) { sechdr = &uctx->meta->m_sectbl[secidx]; text = (char *)module->module_base; text += sechdr->sh_virtual_addr; } } mark += sprintf(mark,"",(void *)text); mark += sprintf(mark,""); } module++; } mark += sprintf(mark,"\n"); } static void winnt_mourn_inferior (struct target_ops * t) { if (inferior_ptid.pid) winnt_plist_remove(inferior_ptid.pid); x86_cleanup_dregs(); inf_child_maybe_unpush_target(t); inf_child_mourn_inferior(t); } static void winnt_abandon (winnt_process * pidinfo) { inferior_ptid = null_ptid; winnt_plist_remove(pidinfo->pid); } ssize_t winnt_xfer_solibs( struct winnt_process * pidinfo, gdb_byte * readbuf, ULONGEST offset, ULONGEST len) { size_t buflen; if (!pidinfo->solibs) return -1; buflen = strlen(pidinfo->solibs); if (offset >= buflen) return 0; if (len > (buflen - offset)) len = buflen - offset; memcpy(readbuf,pidinfo->solibs + offset,len); return len; } static enum target_xfer_status winnt_xfer_partial( struct target_ops * t, enum target_object object, const char * annex, gdb_byte * readbuf, const gdb_byte * writebuf, ULONGEST offset, ULONGEST len, ULONGEST * nxfered) { ssize_t ret; struct winnt_process * pidinfo; pidinfo = winnt_process_record(inferior_ptid.pid); if (readbuf && writebuf) winnt_error("internal error: both readbuf and writebuf are non-null."); if (!readbuf && !writebuf) winnt_error("internal error: both readbuf and writebuf are null."); if (!nxfered) winnt_error("internal error: nxfered is null."); switch (object) { case TARGET_OBJECT_MEMORY: if (!pidinfo) return TARGET_XFER_E_IO; ret = (readbuf) ? __dbg_vm_read(pidinfo->pfd,readbuf,len,offset) : __dbg_vm_write(pidinfo->pfd,writebuf,len,offset); break; case TARGET_OBJECT_LIBRARIES: if (!pidinfo) return TARGET_XFER_E_IO; ret = winnt_xfer_solibs(pidinfo,readbuf,offset,len); break; default: ret = t->beneath->to_xfer_partial( t,object,annex, readbuf,writebuf, offset,len,nxfered); break; } if (ret == 0) return TARGET_XFER_EOF; else if (ret < 0) return TARGET_XFER_E_IO; *nxfered = ret; return TARGET_XFER_OK; } static int winnt_thread_alive (struct target_ops * t, ptid_t ptid) { (void)t; (void)ptid; return true; } static void winnt_interrupt (struct target_ops * t, ptid_t ptid) { (void)t; (void)ptid; } static void winnt_files_info (struct target_ops * t) { (void)t; } static nfds_t winnt_poll_one_init (struct pollfd * pfds, pid_t pid) { winnt_process * pdbg; winnt_process * pcap; for (pdbg=plist, pcap=&plist[pcnt]; pdbgpid == pid) { pfds->fd = pdbg->pfd; pfds->events = POLLIN; return 1; } } return 0; } static nfds_t winnt_poll_init (struct pollfd * pfds) { winnt_process * pdbg; winnt_process * pcap; struct pollfd * pfd; for (pfd=pfds, pdbg=plist, pcap=&plist[pcnt]; pdbgpid) { pfd->fd = pdbg->pfd; pfd->events = POLLIN; pfd++; } } return pfd - pfds; } static void winnt_close (struct target_ops * t) { } static void winnt_xclose (struct target_ops * t) { } static void winnt_set_thread_context_state(struct winnt_thread * thread, int state) { thread->regctx.uc_context_flags = state; } static void winnt_add_thread(int pfd, ptid_t ptid) { pid_t pid; struct winnt_process * pidinfo; struct winnt_thread * thread; mcontext_t * tctx; pid = ptid_get_pid(ptid); pidinfo = winnt_process_record(pid); if (!(thread = (struct winnt_thread *)calloc(1,sizeof(*thread)))) winnt_perror("could not allocate thread record.",pid); if (__dbg_regs_fetch(pfd,ptid.tid,&thread->regctx) < 0) winnt_perror("could not fetch registers for thread.",pid); tctx = &thread->regctx; tctx->uc_dr0 = pidinfo->dr_cache[0]; tctx->uc_dr1 = pidinfo->dr_cache[1]; tctx->uc_dr2 = pidinfo->dr_cache[2]; tctx->uc_dr3 = pidinfo->dr_cache[3]; tctx->uc_dr6 = X86_DR_RTM_MASK; tctx->uc_dr7 = pidinfo->dr_cache[7]; winnt_set_thread_context_state( thread, WINNT_THREAD_CONTEXT_READY); if (__dbg_regs_store(pfd,ptid.tid,tctx) < 0) winnt_perror("could not store registers for thread.",pid); thread->next = pidinfo->threads; pidinfo->threads = thread; thread->process = pidinfo; thread->tid = ptid.tid; add_thread(ptid); } static struct winnt_thread * winnt_get_thread(struct winnt_process * pidinfo, pid_t tid) { struct winnt_thread * thread; for (thread=pidinfo->threads; thread; thread=thread->next) if (thread->tid == tid) return thread; return 0; } static struct winnt_thread * winnt_get_thread_from_ptid(ptid_t ptid) { struct winnt_process * pidinfo; if ((pidinfo = winnt_process_record(ptid.pid))) return winnt_get_thread(pidinfo,ptid.tid); return 0; } static void winnt_delete_thread(struct __dbg_event * event) { ptid_t ptid; struct winnt_process * process; struct winnt_thread * thread; struct winnt_thread * prev; ptid.pid = event->syspid; ptid.tid = event->systid; ptid.lwp = 0; delete_thread(ptid); if (!(thread = winnt_get_thread_from_ptid(ptid))) return; process = thread->process; if (thread == process->threads) { process->threads = thread->next; } else { prev = process->threads; for (; prev->next != thread; ) prev = prev->next; prev->next = thread->next; } if (process->threads) if (inferior_ptid.pid == ptid.pid) if (inferior_ptid.tid == ptid.tid) inferior_ptid.tid = process->threads->tid; free(thread); } static void winnt_respond (int pfd, struct __dbg_event * event, int response) { ptid_t ptid; event->eresponse = response; switch (event->evttype) { case __DBG_STATE_CREATE_PROCESS: ptid = ptid_build(event->syspid,0,event->systid); winnt_add_thread(pfd,ptid); break; case __DBG_STATE_CREATE_THREAD: ptid = ptid_build(event->syspid,0,event->systid); winnt_add_thread(pfd,ptid); break; case __DBG_STATE_EXIT_THREAD: winnt_delete_thread(event); break; case __DBG_STATE_EXIT_PROCESS: target_terminal_ours(); break; default: break; } if (__dbg_event_respond(pfd,event) < 0) winnt_perror("failed to respond to debug event",pfd); event->syspid = 0; event->systid = 0; } static void winnt_prepare (struct target_ops * t, pid_t pid, int pfd, int attached) { int ret; struct inferior * cinf; struct __dbg_event * event; struct winnt_process * pidinfo; if (!target_is_pushed(t)) push_target(t); disable_breakpoints_in_shlibs(); clear_proceed_status(0); init_wait_for_inferior(); if (!(cinf = current_inferior())) winnt_error("failed to obtain current inferior"); if (!(pidinfo = winnt_process_record(pid))) winnt_perror("internal error: record not found",pid); event = &pidinfo->event; inferior_ptid = pid_to_ptid (pid); cinf->attach_flag = attached; inferior_appeared(cinf,pid); init_thread_list(); target_terminal_init(); target_terminal_inferior(); while (1) { do { ret = __dbg_event_acquire(pfd,event); } while ((ret < 0) && (errno == EINTR)); if (ret < 0) winnt_perror("failed to acquire preliminary debug event",pid); if ((event->evttype == __DBG_STATE_CREATE_PROCESS) && !attached) if (__dbg_resume_thread(pfd,event->systid) < 0) winnt_perror("failed to resume first thread",pid); inferior_ptid.pid = event->syspid; inferior_ptid.tid = event->systid; switch (event->evttype) { case __DBG_STATE_EXCEPTION: case __DBG_STATE_BREAKPOINT: case __DBG_STATE_SINGLE_STEP: pidinfo->syspid = event->syspid; pidinfo->systid = event->systid; target_terminal_ours(); return; case __DBG_STATE_EXIT_PROCESS: winnt_respond(pfd,event,__DBG_RESPONSE_CONTINUE); winnt_mourn_inferior(t); case __DBG_STATE_CREATE_PROCESS: case __DBG_STATE_CREATE_THREAD: case __DBG_STATE_IDLE: case __DBG_STATE_REPLY_PENDING: case __DBG_STATE_DLL_LOAD: case __DBG_STATE_DLL_UNLOAD: case __DBG_STATE_EXIT_THREAD: winnt_respond(pfd,event,__DBG_RESPONSE_CONTINUE); } } } static void winnt_fetch_registers ( struct target_ops * t, struct regcache * rcache, int regnum) { pid_t tid; struct winnt_thread * thread; tid = inferior_ptid.tid; if (!(thread = winnt_get_thread_from_ptid(inferior_ptid))) winnt_perror("internal error: thread record not found",tid); if (sizeof(uintptr_t) == 8) amd64_winnt_fetch_registers( rcache,regnum, thread); else i386_winnt_fetch_registers( rcache,regnum, thread); } static void winnt_store_registers ( struct target_ops * t, struct regcache * rcache, int regnum) { pid_t tid; struct winnt_thread * thread; tid = inferior_ptid.tid; if (!(thread = winnt_get_thread_from_ptid(inferior_ptid))) winnt_perror("internal error: thread record not found",tid); if (sizeof(uintptr_t) == 8) amd64_winnt_store_registers( rcache,regnum, thread); else i386_winnt_store_registers( rcache,regnum, thread); } static void winnt_attach (struct target_ops * t, const char * args, int from_tty) { pid_t pid; int pfd; if ((pid = parse_pid_to_attach(args)) < 0) { winnt_error ("cannot parse pid to attach"); } if ((pfd = __dbg_attach(pid)) < 0) { winnt_perror ("cannot attach to process",pid); } if (__dbg_rbreak(pfd) < 0) { __dbg_detach(pfd); close(pfd); winnt_perror ("could not issue a breakpoint in process",pid); } if (winnt_plist_add(pid,pfd) < 0) { __dbg_detach(pfd); close(pfd); winnt_error ("could not expand debuggee list"); } winnt_prepare(t,pid,pfd,from_tty); winnt_get_modules(winnt_process_record(pid)); } static void winnt_detach (struct target_ops * t, const char * args, int from_tty) { pid_t pid; winnt_process * pidinfo; if ((pid = ptid_get_pid(inferior_ptid)) < 0) winnt_error ("cannot determine pid to detach"); if (!(pidinfo = winnt_process_record(pid))) winnt_perror ("debuggee record does not exist",pid); if (__dbg_detach(pidinfo->pfd) < 0) winnt_perror ("could not detach from process",pid); if (close(pidinfo->pfd) < 0) winnt_perror ("failed to close process file descriptor",pid); detach_inferior(pidinfo->syspid); winnt_abandon(pidinfo); winnt_mourn_inferior(t); exec_file_clear(from_tty); } static int winnt_exception_filter_match_code( struct __dbg_event * event, struct winnt_exception_filter * filter) { if (!filter->exception_code) return 1; if (!event->exception_record) return 0; if (filter->exception_code != event->exception_record->exception_code) return 0; if (filter->exception_flags & WINNT_EXCEPTION_FIRST_CHANCE) if (event->exception_priority) return 1; if (filter->exception_flags & WINNT_EXCEPTION_SECOND_CHANCE) if (!event->exception_priority) return 1; return 0; } static int winnt_exception_filter_match_module( struct __dbg_event * event, struct winnt_exception_filter * filter, struct winnt_process* pidinfo) { struct __dbg_module_info * module; struct __dbg_module_info * module_cap; struct winnt_thread * thread; struct pe_unit_ctx * uctx; struct pe_meta_sec_hdr * sechdr; int secidx; char * addr; char * mark; char * text; char * text_cap; thread = winnt_get_thread(pidinfo,event->systid); addr = (char *)thread->regctx.uc_rip; module_cap = &pidinfo->modules[pidinfo->nmodules]; for (module=pidinfo->modules; modulemodule_ctx)) { secidx = pe_get_named_section_index( uctx->meta,".text"); if (secidx >= 0) { mark = 0; sechdr = &uctx->meta->m_sectbl[secidx]; text = (char *)module->module_base; text += sechdr->sh_virtual_addr; text_cap = text + sechdr->sh_virtual_size; if ((addr >= text) && (addr < text_cap)) mark = strrchr(module->module_name,'/'); if (mark && !filter->exception_module) return 1; if (mark && filter->exception_module) if (!(strcmp(++mark,filter->exception_module))) return 1; } } } return 0; } static int winnt_exception_filter_match(struct __dbg_event * event) { struct winnt_process * pidinfo; struct winnt_exception_filter * filter = winnt_exception_filters; switch (event->evttype) { case __DBG_STATE_EXCEPTION: case __DBG_STATE_BREAKPOINT: case __DBG_STATE_SINGLE_STEP: break; default: return 0; } if (!(pidinfo = winnt_process_record(event->syspid))) return 0; for (; filter->exception_flags; filter++) if (winnt_exception_filter_match_code(event,filter)) if (winnt_exception_filter_match_module(event,filter,pidinfo)) return 1; return 0; } static enum gdb_signal winnt_dbg_signal(struct __dbg_event * event) { switch (event->exception_record->exception_code) { case WINNT_STATUS_ACCESS_VIOLATION: return GDB_SIGNAL_SEGV; default: return GDB_SIGNAL_UNKNOWN; } } static struct __dbg_event * winnt_wait_event(ptid_t ptid) { struct __dbg_event event; struct winnt_process * pdbg; struct winnt_process * pcap; struct winnt_process * pidinfo; struct winnt_thread * thread; struct pollfd pollfdbuf[512]; struct pollfd * pfds; struct pollfd * pfd; nfds_t nfds,i; if (ptid.pid < 0) for (pdbg=plist, pcap=&plist[pcnt]; pdbgevent.systid) return &pdbg->event; if (ptid.pid > 0) { if (!(pidinfo = winnt_process_record(event.syspid))) winnt_perror("internal error: record not found",event.syspid); if (pidinfo->event.systid) return &pidinfo->event; } if (pcnt*sizeof(*pfds) < sizeof(pollfdbuf)) pfds = pollfdbuf; else if (!(pfds = (struct pollfd *)calloc(pcnt,sizeof(*pfds)))) return 0; nfds = (ptid.pid > 0) ? winnt_poll_one_init(pfds,ptid.pid) : winnt_poll_init(pfds); if (poll(pfds,nfds,-1) < 0) return 0; for (i=0, pfd=0; ifd,&event) < 0) return 0; if (!(pidinfo = winnt_process_record(event.syspid))) winnt_perror("internal error: record not found",event.syspid); memcpy(&pidinfo->event,&event,sizeof(event)); for (thread=pidinfo->threads; thread; thread=thread->next) { __dbg_regs_fetch( pidinfo->pfd, thread->tid, &thread->regctx); winnt_set_thread_context_state( thread, WINNT_THREAD_CONTEXT_READY); } return &pidinfo->event; } static ptid_t winnt_wait( struct target_ops * t, ptid_t ptid, struct target_waitstatus * waitstatus, int target_options) { int pfd; struct __dbg_event * event; struct winnt_process * process; int fskip; int eresponse; target_terminal_ours(); do { if (!(event = winnt_wait_event(ptid))) return null_ptid; if ((fskip = winnt_exception_filter_match(event))) { if (!(process = winnt_process_record(event->syspid))) return null_ptid; if (event->exception_priority) eresponse = __DBG_RESPONSE_EXCEPTION_NOT_HANDLED; else eresponse = __DBG_RESPONSE_CONTINUE; winnt_respond(process->pfd,event,eresponse); } } while (fskip); if (!(process = winnt_process_record(event->syspid))) return null_ptid; pfd = process->pfd; inferior_ptid.pid = event->syspid; inferior_ptid.tid = event->systid; switch (event->evttype) { case __DBG_STATE_EXCEPTION: waitstatus->kind = TARGET_WAITKIND_STOPPED; waitstatus->value.sig = winnt_dbg_signal(event); break; case __DBG_STATE_BREAKPOINT: case __DBG_STATE_SINGLE_STEP: waitstatus->kind = TARGET_WAITKIND_STOPPED; waitstatus->value.sig = GDB_SIGNAL_TRAP; break; case __DBG_STATE_CREATE_THREAD: waitstatus->kind = TARGET_WAITKIND_THREAD_CREATED; waitstatus->value.integer = event->systid; winnt_respond(pfd,event,__DBG_RESPONSE_CONTINUE); break; case __DBG_STATE_EXIT_THREAD: waitstatus->kind = TARGET_WAITKIND_THREAD_EXITED; waitstatus->value.integer = event->systid; winnt_respond(pfd,event,__DBG_RESPONSE_CONTINUE); break; case __DBG_STATE_CREATE_PROCESS: waitstatus->kind = TARGET_WAITKIND_SPURIOUS; waitstatus->value.integer = 0; break; case __DBG_STATE_EXIT_PROCESS: waitstatus->kind = TARGET_WAITKIND_EXITED; waitstatus->value.integer = *event->process_exit_code; winnt_respond(pfd,event,__DBG_RESPONSE_CONTINUE); break; case __DBG_STATE_DLL_LOAD: waitstatus->kind = TARGET_WAITKIND_LOADED; waitstatus->value.integer = 0; winnt_get_modules(process); break; case __DBG_STATE_DLL_UNLOAD: waitstatus->kind = TARGET_WAITKIND_LOADED; waitstatus->value.integer = 0; winnt_get_modules(process); break; case __DBG_STATE_IDLE: case __DBG_STATE_REPLY_PENDING: waitstatus->kind = TARGET_WAITKIND_SPURIOUS; waitstatus->value.integer = 0; break; } return inferior_ptid; } static void winnt_resume_one(ptid_t ptid, int step, enum gdb_signal sig) { pid_t tid; struct winnt_process * process; struct winnt_thread * thread; mcontext_t * tctx; if ((tid = ptid.tid) <= 0) if ((process = winnt_process_record(ptid.pid))) tid = process->systid; if (!(thread = winnt_get_thread_from_ptid(ptid))) winnt_perror("internal error: thread record not found",tid); process = thread->process; tctx = &thread->regctx; if (process->dr_state) { tctx->uc_dr0 = process->dr_cache[0]; tctx->uc_dr1 = process->dr_cache[1]; tctx->uc_dr2 = process->dr_cache[2]; tctx->uc_dr3 = process->dr_cache[3]; tctx->uc_dr6 = X86_DR_RTM_MASK; tctx->uc_dr7 = process->dr_cache[7]; } if (step && !(tctx->uc_eflags & X86_EFLAGS_TRACE)) { tctx->uc_eflags |= X86_EFLAGS_TRACE; winnt_set_thread_context_state( thread, WINNT_THREAD_CONTEXT_DIRTY); } if (process->dr_state || tctx->uc_context_flags) __dbg_regs_store(process->pfd,tid,tctx); if (tid == process->event.systid) { process->event.eresponse = __DBG_RESPONSE_CONTINUE; __dbg_event_respond( process->pfd, &process->event); while (__dbg_resume_thread(process->pfd,tid) > 1) (void)0; process->event.syspid = 0; process->event.systid = 0; } } static void winnt_resume_process(pid_t pid, int step, enum gdb_signal sig) { struct winnt_process * pdbg; struct winnt_thread * thread; ptid_t ptid; if (!(pdbg = winnt_process_record(pid))) return; for (thread=pdbg->threads; thread; thread=thread->next) { ptid.pid = pdbg->syspid; ptid.tid = thread->tid; ptid.lwp = 0; (thread->tid == inferior_ptid.tid) ? winnt_resume_one(ptid,step,sig) : winnt_resume_one(ptid,0,sig); } } static void winnt_resume_all(int step, enum gdb_signal sig) { struct winnt_process * pdbg; struct winnt_process * pcap; struct winnt_thread * thread; ptid_t ptid; for (pdbg=plist, pcap=&plist[pcnt]; pdbgpfd && (thread = pdbg->threads)) { for (; thread; ) { ptid.pid = pdbg->syspid; ptid.tid = thread->tid; ptid.lwp = 0; (thread->tid == inferior_ptid.tid) ? winnt_resume_one(ptid,step,sig) : winnt_resume_one(ptid,0,sig); thread = thread->next; } } } } static void winnt_resume ( struct target_ops * t, ptid_t ptid, int step, enum gdb_signal sig) { ptid_equal(ptid,minus_one_ptid) ? winnt_resume_all(step,sig) : ptid.tid ? winnt_resume_one(ptid,step,sig) : winnt_resume_process(ptid.pid,step,sig); } static void winnt_kill (struct target_ops * t) { struct inferior * cinf; struct winnt_process * pidinfo; if (!(cinf = current_inferior())) winnt_error("failed to obtain current inferior"); if (!(pidinfo = winnt_process_record(cinf->pid))) winnt_perror("internal error: record not found",cinf->pid); if (__dbg_kill(pidinfo->pfd) < 0) winnt_perror("failed to kill current inferior",cinf->pid); winnt_abandon(pidinfo); winnt_mourn_inferior(t); } static void winnt_create_inferior( struct target_ops * t, char * exec_file, char * args, char ** envp, int from_tty) { int pfd; pid_t pid; size_t arglen; char * argbuf; char ** argv; /* validate */ if (!exec_file) winnt_error("Executable not set; use `target exec'."); /* assume no folded white space, add final null termination */ arglen = strlen(args); arglen++; if (!(argbuf = (char *)calloc(2*arglen,1))) winnt_error("Failed to allocate argument string buffer."); /* extra pointer for exec_file (argv[0]) */ arglen++; if (!(argv = (char **)calloc(arglen,sizeof(char *)))) winnt_error("Failed to allocate argument vector buffer."); arglen--; /* argv */ argv[0] = exec_file; if (__cmd_args_to_argv(args,argbuf,2*arglen,&argv[1],arglen) < 0) winnt_error("Failed to parse command-line arguments."); /* spawn */ if ((pfd = __dbg_spawn(exec_file,argv,envp,0)) < 0) winnt_error("Failed to spawn executable."); /* syspid */ if ((pid = __dbg_query_syspid(pfd)) < 0) { __dbg_kill(pfd); close(pfd); winnt_error("Failed to obtain syspid (should never happen)."); } /* debuggee list */ if (winnt_plist_add(pid,pfd) < 0) { __dbg_kill(pfd); close(pfd); winnt_error ("could not expand debuggee list"); } /* init loop */ winnt_prepare(t,pid,pfd,0); winnt_get_modules(winnt_process_record(pid)); } static char * winnt_pid_to_str (struct target_ops * t, ptid_t ptid) { if (ptid.tid) sprintf(outbuf,"Thread %d:%ld",ptid.pid,ptid.tid); else sprintf(outbuf,"Process %d",ptid.pid); return outbuf; } static int winnt_supports_multi_process(struct target_ops * t) { return 1; } static int winnt_perk_init(void) { char * argv[2]; if (pe_dctx) return 0; argv[0] = (char *)get_gdb_program_name(); argv[1] = 0; return pe_get_driver_ctx(argv,0,0,0,&pe_dctx); } #define WINNT_DR_HANDLER(handler) \ winnt_dr_ ## handler #define WINNT_SET_DR_LOW_HANDLER(handler) \ x86_dr_low.handler = WINNT_DR_HANDLER(handler) static void winnt_dr_set_addr(int idx, uintptr_t any) { pid_t pid; struct winnt_process * pidinfo; pid = ptid_get_pid(inferior_ptid); pidinfo = winnt_process_record(pid); pidinfo->dr_cache[idx] = any; pidinfo->dr_state = WINNT_DR_STATE_DIRTY; } static uintptr_t winnt_dr_get_addr(int idx) { pid_t pid; struct winnt_process * pidinfo; pid = ptid_get_pid(inferior_ptid); pidinfo = winnt_process_record(pid); return pidinfo->dr_cache[idx]; } static void winnt_dr_set_control(unsigned long ctrl) { winnt_dr_set_addr(7,ctrl); } static unsigned long winnt_dr_get_control(void) { return winnt_dr_get_addr(7); } static unsigned long winnt_dr_get_status(void) { return winnt_dr_get_addr(6); } static void winnt_init_dr_low(void) { WINNT_SET_DR_LOW_HANDLER(set_control); WINNT_SET_DR_LOW_HANDLER(get_control); WINNT_SET_DR_LOW_HANDLER(get_status); WINNT_SET_DR_LOW_HANDLER(set_addr); WINNT_SET_DR_LOW_HANDLER(get_addr); x86_set_debug_register_length(sizeof(uintptr_t)); } static target_ops * winnt_target_alloc (void) { target_ops * t = inf_child_target(); t->to_attach_no_wait = 1; t->to_has_thread_control = 1; t->to_close = winnt_close; t->to_xclose = winnt_xclose; t->to_attach = winnt_attach; t->to_detach = winnt_detach; t->to_wait = winnt_wait; t->to_resume = winnt_resume; t->to_kill = winnt_kill; t->to_mourn_inferior = winnt_mourn_inferior; t->to_create_inferior = winnt_create_inferior; t->to_pid_to_str = winnt_pid_to_str; t->to_pid_to_exec_file = winnt_pid_to_exec_file; t->to_fetch_registers = winnt_fetch_registers; t->to_store_registers = winnt_store_registers; t->to_xfer_partial = winnt_xfer_partial; t->to_files_info = winnt_files_info; t->to_thread_alive = winnt_thread_alive; t->to_interrupt = winnt_interrupt; t->to_get_ada_task_ptid = winnt_get_ada_task_ptid; t->to_supports_multi_process = winnt_supports_multi_process; x86_use_watchpoints(t); winnt_init_dr_low(); if (winnt_perk_init() < 0) return 0; return ((outbuf = (char *)calloc(1,WINNT_OUTBUF_SIZE))) ? t : 0; } extern initialize_file_ftype _initialize_winnt_nat; extern void amd64_winnt_init_reg_offsets(void); void _initialize_winnt_nat(void) { add_target(winnt_target_alloc()); amd64_winnt_init_reg_offsets(); }