/* * 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 #ifndef PATH_MAX #define PATH_MAX MAX_PATH #endif #include "debugger.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(winedbg); struct search_list { char* path; struct search_list* next; }; struct open_file_list { char* path; char* real_path; struct open_file_list* next; unsigned int size; signed int nlines; unsigned int* linelist; }; static struct open_file_list* source_ofiles; static struct search_list* source_list_head; static char source_current_file[PATH_MAX]; static int source_start_line = -1; static int source_end_line = -1; void source_show_path(void) { struct search_list* sl; dbg_printf("Search list:\n"); for (sl = source_list_head; sl; sl = sl->next) dbg_printf("\t%s\n", sl->path); dbg_printf("\n"); } void source_add_path(const char* path) { struct search_list* sl; if (!(sl = HeapAlloc(GetProcessHeap(), 0, sizeof(struct search_list)))) return; sl->next = source_list_head; sl->path = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(path) + 1), path); source_list_head = sl; } void source_nuke_path(void) { struct search_list* sl; struct search_list* nxt; for (sl = source_list_head; sl; sl = nxt) { nxt = sl->next; HeapFree(GetProcessHeap(), 0, sl->path); HeapFree(GetProcessHeap(), 0, sl); } source_list_head = NULL; } static void* source_map_file(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 source_unmap_file(void* addr, HANDLE hMap) { UnmapViewOfFile(addr); CloseHandle(hMap); } static struct open_file_list* source_search_open_file(const char* name) { struct open_file_list* ol; for (ol = source_ofiles; ol; ol = ol->next) { if (strcmp(ol->path, name) == 0) break; } return ol; } static int source_display(const char* sourcefile, int start, int end) { char* addr; int i; struct open_file_list* ol; int nlines; const char* basename = NULL; char* pnt; int rtn; struct search_list* 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 = source_search_open_file(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 = source_search_open_file(basename); } if (ol == NULL) { /* * Crapola. We need to try and open the file. */ status = GetFileAttributes(sourcefile); if (status != INVALID_FILE_ATTRIBUTES) { strcpy(tmppath, sourcefile); } else if ((status = GetFileAttributes(basename)) != INVALID_FILE_ATTRIBUTES) { strcpy(tmppath, basename); } else { for (sl = source_list_head; 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 != INVALID_FILE_ATTRIBUTES) break; } if (sl == NULL) { if (dbg_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); input_read_line(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 = INVALID_FILE_ATTRIBUTES; strcpy(tmppath, sourcefile); } if (status == INVALID_FILE_ATTRIBUTES) { /* * OK, I guess the user doesn't really want to see it * after all. */ ol = HeapAlloc(GetProcessHeap(), 0, sizeof(*ol)); ol->path = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(sourcefile) + 1), sourcefile); ol->real_path = NULL; ol->next = source_ofiles; ol->nlines = 0; ol->linelist = NULL; source_ofiles = ol; dbg_printf("Unable to open file %s\n", tmppath); return FALSE; } } } /* * Create header for file. */ ol = HeapAlloc(GetProcessHeap(), 0, sizeof(*ol)); ol->path = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(sourcefile) + 1), sourcefile); ol->real_path = strcpy(HeapAlloc(GetProcessHeap(), 0, strlen(tmppath) + 1), tmppath); ol->next = source_ofiles; ol->nlines = 0; ol->linelist = NULL; ol->size = 0; source_ofiles = ol; addr = source_map_file(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 = HeapAlloc(GetProcessHeap(), 0, 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 = source_map_file(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); } dbg_printf("%d\t%s\n", i + 1, buffer); } source_unmap_file(addr, hMap); return rtn; } void source_list(IMAGEHLP_LINE* src1, IMAGEHLP_LINE* src2, int delta) { int end; int start; const char* sourcefile; /* * We need to see what source file we need. Hopefully we only have * one specified, otherwise we might as well punt. */ if (src1 && src2 && src1->FileName && src2->FileName && strcmp(src1->FileName, src2->FileName) != 0) { dbg_printf("Ambiguous source file specification.\n"); return; } sourcefile = NULL; if (src1 && src1->FileName) sourcefile = src1->FileName; if (!sourcefile && src2 && src2->FileName) sourcefile = src2->FileName; if (!sourcefile) sourcefile = source_current_file; /* * Now figure out the line number range to be listed. */ start = end = -1; if (src1) start = src1->LineNumber; if (src2) end = src2->LineNumber; if (start == -1 && end == -1) { if (delta < 0) { end = source_start_line; start = end + delta; } else { start = source_end_line; 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. */ source_display(sourcefile, start, end); if (sourcefile != source_current_file) strcpy(source_current_file, sourcefile); source_start_line = start; source_end_line = end; } void source_list_from_addr(const ADDRESS* addr, int nlines) { IMAGEHLP_LINE il; DWORD lin; if (!addr) { ADDRESS la; memory_get_current_pc(&la); lin = (unsigned long)memory_to_linear_addr(&la); } else lin = (unsigned long)memory_to_linear_addr(addr); il.SizeOfStruct = sizeof(il); if (SymGetLineFromAddr(dbg_curr_process->handle, lin, NULL, &il)) source_list(&il, NULL, nlines); }