/* * File source.c - source file handling for internal debugger. * * Copyright (C) 1997, Eric Youngdale. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "config.h" #include #include #include #ifdef HAVE_SYS_MMAN_H #include #endif #include #include #include #include #ifdef HAVE_UNISTD_H # include #endif #ifndef PATH_MAX #define PATH_MAX MAX_PATH #endif #include "debugger.h" struct searchlist { char * path; struct searchlist * next; }; struct open_filelist { char * path; char * real_path; struct open_filelist * next; unsigned int size; signed int nlines; unsigned int * linelist; }; static struct open_filelist * ofiles; static struct searchlist * listhead; static char DEBUG_current_sourcefile[PATH_MAX]; static int DEBUG_start_sourceline = -1; static int DEBUG_end_sourceline = -1; void DEBUG_ShowDir(void) { struct searchlist * sl; DEBUG_Printf(DBG_CHN_MESG,"Search list :\n"); for(sl = listhead; sl; sl = sl->next) { DEBUG_Printf(DBG_CHN_MESG, "\t%s\n", sl->path); } DEBUG_Printf(DBG_CHN_MESG, "\n"); } void DEBUG_AddPath(const char * path) { struct searchlist * sl; sl = (struct searchlist *) DBG_alloc(sizeof(struct searchlist)); if( sl == NULL ) { return; } sl->next = listhead; sl->path = DBG_strdup(path); listhead = sl; } void DEBUG_NukePath(void) { struct searchlist * sl; struct searchlist * nxt; for(sl = listhead; sl; sl = nxt) { nxt = sl->next; DBG_free(sl->path); DBG_free(sl); } listhead = NULL; } static void* DEBUG_MapFile(const char* name, HANDLE* hMap, unsigned* size) { HANDLE hFile; hFile = CreateFile(name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE) return (void*)-1; if (size != NULL && (*size = GetFileSize(hFile, NULL)) == -1) return (void*)-1; *hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); CloseHandle(hFile); if (!*hMap) return (void*)-1; return MapViewOfFile(*hMap, FILE_MAP_READ, 0, 0, 0); } static void DEBUG_UnmapFile(void* addr, HANDLE hMap) { UnmapViewOfFile(addr); CloseHandle(hMap); } static struct open_filelist* DEBUG_SearchOpenFile(const char* name) { struct open_filelist* ol; for (ol = ofiles; ol; ol = ol->next) { if (strcmp(ol->path, name) == 0) break; } return ol; } static int DEBUG_DisplaySource(char * sourcefile, int start, int end) { char* addr; int i; struct open_filelist* ol; int nlines; char* basename = NULL; char* pnt; int rtn; struct searchlist* sl; HANDLE hMap; DWORD status; char tmppath[PATH_MAX]; /* * First see whether we have the file open already. If so, then * use that, otherwise we have to try and open it. */ ol = DEBUG_SearchOpenFile(sourcefile); if ( ol == NULL ) { /* * Try again, stripping the path from the opened file. */ basename = strrchr(sourcefile, '\\' ); if ( !basename ) basename = strrchr(sourcefile, '/' ); if ( !basename ) basename = sourcefile; else basename++; ol = DEBUG_SearchOpenFile(basename); } if ( ol == NULL ) { /* * Crapola. We need to try and open the file. */ status = GetFileAttributes(sourcefile); if ( status != -1 ) { strcpy(tmppath, sourcefile); } else if ( (status = GetFileAttributes(basename)) != -1 ) { strcpy(tmppath, basename); } else { for (sl = listhead; sl; sl = sl->next) { strcpy(tmppath, sl->path); if ( tmppath[strlen(tmppath)-1] != '/' && tmppath[strlen(tmppath)-1] != '\\' ) { strcat(tmppath, "/"); } /* * Now append the base file name. */ strcat(tmppath, basename); status = GetFileAttributes(tmppath); if ( status != -1 ) break; } if ( sl == NULL ) { if (DEBUG_InteractiveP) { char zbuf[256]; /* * Still couldn't find it. Ask user for path to add. */ snprintf(zbuf, sizeof(zbuf), "Enter path to file '%s': ", sourcefile); DEBUG_ReadLine(zbuf, tmppath, sizeof(tmppath)); if ( tmppath[strlen(tmppath)-1] != '/' ) { strcat(tmppath, "/"); } /* * Now append the base file name. */ strcat(tmppath, basename); status = GetFileAttributes(tmppath); } else { status = -1; strcpy(tmppath, sourcefile); } if ( status == -1 ) { /* * OK, I guess the user doesn't really want to see it * after all. */ ol = (struct open_filelist *) DBG_alloc(sizeof(*ol)); ol->path = DBG_strdup(sourcefile); ol->real_path = NULL; ol->next = ofiles; ol->nlines = 0; ol->linelist = NULL; ofiles = ol; DEBUG_Printf(DBG_CHN_MESG,"Unable to open file %s\n", tmppath); return FALSE; } } } /* * Create header for file. */ ol = (struct open_filelist *) DBG_alloc(sizeof(*ol)); ol->path = DBG_strdup(sourcefile); ol->real_path = DBG_strdup(tmppath); ol->next = ofiles; ol->nlines = 0; ol->linelist = NULL; ol->size = 0; ofiles = ol; addr = DEBUG_MapFile(tmppath, &hMap, &ol->size); if ( addr == (char *) -1 ) { return FALSE; } /* * Now build up the line number mapping table. */ ol->nlines = 1; pnt = addr; while (pnt < addr + ol->size ) { if ( *pnt++ == '\n' ) { ol->nlines++; } } ol->nlines++; ol->linelist = (unsigned int*) DBG_alloc( ol->nlines * sizeof(unsigned int) ); nlines = 0; pnt = addr; ol->linelist[nlines++] = 0; while(pnt < addr + ol->size ) { if( *pnt++ == '\n' ) { ol->linelist[nlines++] = pnt - addr; } } ol->linelist[nlines++] = pnt - addr; } else { addr = DEBUG_MapFile(ol->real_path, &hMap, NULL); if ( addr == (char *) -1 ) { return FALSE; } } /* * All we need to do is to display the source lines here. */ rtn = FALSE; for (i = start - 1; i <= end - 1; i++) { char buffer[1024]; if (i < 0 || i >= ol->nlines - 1) { continue; } rtn = TRUE; memset(&buffer, 0, sizeof(buffer)); if ( ol->linelist[i+1] != ol->linelist[i] ) { memcpy(&buffer, addr + ol->linelist[i], (ol->linelist[i+1] - ol->linelist[i]) - 1); } DEBUG_Printf(DBG_CHN_MESG,"%d\t%s\n", i + 1, buffer); } DEBUG_UnmapFile(addr, hMap); return rtn; } void DEBUG_List(struct list_id * source1, struct list_id * source2, int delta) { int end; int rtn; int start; char * sourcefile; /* * We need to see what source file we need. Hopefully we only have * one specified, otherwise we might as well punt. */ if( source1 != NULL && source2 != NULL && source1->sourcefile != NULL && source2->sourcefile != NULL && strcmp(source1->sourcefile, source2->sourcefile) != 0 ) { DEBUG_Printf(DBG_CHN_MESG, "Ambiguous source file specification.\n"); return; } sourcefile = NULL; if( source1 != NULL && source1->sourcefile != NULL ) { sourcefile = source1->sourcefile; } if( sourcefile == NULL && source2 != NULL && source2->sourcefile != NULL ) { sourcefile = source2->sourcefile; } if( sourcefile == NULL ) { sourcefile = (char *) &DEBUG_current_sourcefile; } if( sourcefile == NULL ) { DEBUG_Printf(DBG_CHN_MESG, "No source file specified.\n"); return; } /* * Now figure out the line number range to be listed. */ start = -1; end = -1; if( source1 != NULL ) { start = source1->line; } if( source2 != NULL ) { end = source2->line; } if( start == -1 && end == -1 ) { if( delta < 0 ) { end = DEBUG_start_sourceline; start = end + delta; } else { start = DEBUG_end_sourceline; end = start + delta; } } else if( start == -1 ) { start = end + delta; } else if (end == -1) { end = start + delta; } /* * Now call this function to do the dirty work. */ rtn = DEBUG_DisplaySource(sourcefile, start, end); if( sourcefile != (char *) &DEBUG_current_sourcefile ) { strcpy(DEBUG_current_sourcefile, sourcefile); } DEBUG_start_sourceline = start; DEBUG_end_sourceline = end; } DBG_ADDR DEBUG_LastDisassemble={0,0}; BOOL DEBUG_DisassembleInstruction(DBG_ADDR *addr) { char ch; BOOL ret = TRUE; DEBUG_PrintAddress(addr, DEBUG_CurrThread->dbg_mode, TRUE); DEBUG_Printf(DBG_CHN_MESG, ": "); if (!DEBUG_READ_MEM_VERBOSE((void*)DEBUG_ToLinear(addr), &ch, sizeof(ch))) { DEBUG_Printf(DBG_CHN_MESG, "-- no code --"); ret = FALSE; } else { DEBUG_Disasm(addr, TRUE); } DEBUG_Printf(DBG_CHN_MESG,"\n"); return ret; } void DEBUG_Disassemble(const DBG_VALUE *xstart,const DBG_VALUE *xend,int offset) { int i; DBG_ADDR last; DBG_VALUE end,start; if (xstart) { start = *xstart; DEBUG_GrabAddress(&start, TRUE); } if (xend) { end = *xend; DEBUG_GrabAddress(&end, TRUE); } if (!xstart && !xend) { last = DEBUG_LastDisassemble; if (!last.seg && !last.off) DEBUG_GetCurrentAddress( &last ); for (i=0;i