From: Jean-Paul Mari Date: Wed, 2 Oct 2019 19:02:34 +0000 (-0400) Subject: Worked started for the source tracing X-Git-Tag: v2.1.3-R5^2~36^2~3^2~1 X-Git-Url: http://git.hcoop.net/clinton/Virtual-Jaguar-Rx.git/commitdiff_plain/695f52e357d6a78ebdd05a471cd726ffab2145b0 Worked started for the source tracing --- diff --git a/Win-VS2017/virtualjaguar.vcxproj.filters b/Win-VS2017/virtualjaguar.vcxproj.filters index 6c74ae9..d7b9722 100644 --- a/Win-VS2017/virtualjaguar.vcxproj.filters +++ b/Win-VS2017/virtualjaguar.vcxproj.filters @@ -463,6 +463,24 @@ Source Files\alpine + + Generated Files + + + Source Files\debugger + + + Generated Files + + + Source Files\debugger + + + Generated Files + + + Generated Files + @@ -784,6 +802,12 @@ Header Files\alpine + + Header Files\debugger + + + Header Files\debugger + diff --git a/docs/vj_HistoryNotes.txt b/docs/vj_HistoryNotes.txt index fd9fc6c..b39c710 100644 --- a/docs/vj_HistoryNotes.txt +++ b/docs/vj_HistoryNotes.txt @@ -7,6 +7,7 @@ Release 5 (TBA) 2) Added a specific breakpoint for the M68K address error exception -- Alert box will display a message and then the code will stop 3) Added a HW registers browser window and set a tab for the Blitter +4) Added a source tab in the main window for step into tracing Release 4a (15th August 2019) ----------------------------- @@ -227,8 +228,9 @@ Known issues 15) After a new breakpoint set, the breakpoint list window is not refreshed -- User must perform an operation, such code tracing, to see the breakpoints list update 16) Some ASCII characters may be not displayed correctly --- It depend how the text is displayed, this is related to the QT/HTML encoding done when reading DWARF file +-- Probably depend how the text is displayed, this is related to the QT/HTML encoding done when reading DWARF file 17) Potential legacy crash when leaving emulator in pause mode for a long period of time +-- Need much investigation Cosmetic / UX issues ==================== diff --git a/src/debugger/DBGManager.cpp b/src/debugger/DBGManager.cpp index 3dcb138..d86ecf9 100644 --- a/src/debugger/DBGManager.cpp +++ b/src/debugger/DBGManager.cpp @@ -12,6 +12,7 @@ // JPM Various efforts to set the DWARF format support // JPM 09/15/2018 Support the unsigned char // JPM Oct./2018 Cosmetic changes, added source file search paths, and ELF function name +// JPM Aug./2019 Added new functions mainly for source text lines // // To Do @@ -746,19 +747,33 @@ char *DBGManager_GetLineSrcFromNumLineBaseAdr(size_t Adr, size_t NumLine) // Get number of source code filenames -size_t DBGManager_GetNbFullSourceFilename(void) +size_t DBGManager_GetNbSources(void) { size_t Nbr = 0; if ((DBGType & DBG_ELFDWARF)) { - Nbr = DWARFManager_GetNbFullSourceFilename(); + Nbr = DWARFManager_GetNbSources(); } return Nbr; } +// Get source code filename based on index +char *DBGManager_GetNumSourceFilename(size_t Index) +{ + char *SourceFilename = NULL; + + if ((DBGType & DBG_ELFDWARF)) + { + SourceFilename = DWARFManager_GetNumSourceFilename(Index); + } + + return SourceFilename; +} + + // Get source code filename based on index char *DBGManager_GetNumFullSourceFilename(size_t Index) { @@ -771,3 +786,60 @@ char *DBGManager_GetNumFullSourceFilename(size_t Index) return FullSourceFilename; } + + +// Get number of lines of texts source list from source index +size_t DBGManager_GetSrcNbListPtrFromIndex(size_t Index, bool Used) +{ + size_t NbListPtr = 0; + + if ((DBGType & DBG_ELFDWARF)) + { + NbListPtr = DWARFManager_GetSrcNbListPtrFromIndex(Index, Used); + } + + return NbListPtr; +} + + +// Get pointer to the lines number list from source index +size_t *DBGManager_GetSrcNumLinesPtrFromIndex(size_t Index, bool Used) +{ + size_t *PtrNumLines = NULL; + + if ((DBGType & DBG_ELFDWARF)) + { + PtrNumLines = DWARFManager_GetSrcNumLinesPtrFromIndex(Index, Used); + } + + return PtrNumLines; +} + + +// Get text source list pointers from source index +char **DBGManager_GetSrcListPtrFromIndex(size_t Index, bool Used) +{ + char **PtrSource = NULL; + + if ((DBGType & DBG_ELFDWARF)) + { + PtrSource = DWARFManager_GetSrcListPtrFromIndex(Index, Used); + } + + return PtrSource; +} + + +// Get source language +size_t DBGManager_GetSrcLanguageFromIndex(size_t Index) +{ + size_t Language = 0; + + if ((DBGType & DBG_ELFDWARF)) + { + Language = DWARFManager_GetSrcLanguageFromIndex(Index); + } + + return Language; +} + diff --git a/src/debugger/DBGManager.h b/src/debugger/DBGManager.h index f034621..09cabc1 100644 --- a/src/debugger/DBGManager.h +++ b/src/debugger/DBGManager.h @@ -4,6 +4,16 @@ #define __DBGMANAGER_H__ +// Language tag based in the DW_TAG_... list from the dwarf.h +typedef enum { + DBG_NO_LANG = 0x0, + DBG_LANG_C89 = 0x1, + DBG_LANG_C99 = 0xc, + DBG_LANG_VASM_Assembler = 0x8001, // source from vasm assembler is marked as "DW_LANG_Mips_Assembler" with same value + DBG_END_LANG +}DBGLANGTAG; + +// Debug types typedef enum { DBG_NO_TYPE = 0x0, DBG_ELF = 0x1, @@ -227,15 +237,20 @@ extern size_t DBGManager_GetType(void); extern void DBGManager_Reset(void); extern void DBGManager_Close(void); extern void DBGManager_SourceFileSearchPathsSet(char *ListPaths); +extern size_t DBGManager_GetNbSources(void); // Source text lines manager extern size_t DBGManager_GetNumLineFromAdr(size_t Adr, size_t Tag); extern char *DBGManager_GetLineSrcFromAdr(size_t Adr, size_t Tag); extern char *DBGManager_GetLineSrcFromAdrNumLine(size_t Adr, size_t NumLine); extern char *DBGManager_GetLineSrcFromNumLineBaseAdr(size_t Adr, size_t NumLine); +extern char **DBGManager_GetSrcListPtrFromIndex(size_t Index, bool Used); +extern size_t DBGManager_GetSrcNbListPtrFromIndex(size_t Index, bool Used); +extern size_t *DBGManager_GetSrcNumLinesPtrFromIndex(size_t Index, bool Used); // General manager extern char *DBGManager_GetVariableValueFromAdr(size_t Adr, size_t TypeEncoding, size_t TypeByteSize); +extern size_t DBGManager_GetSrcLanguageFromIndex(size_t Index); // Functions manager extern char *DBGManager_GetFunctionName(size_t Adr); @@ -246,8 +261,8 @@ extern size_t DBGManager_GetAdrFromSymbolName(char *SymbolName); // Source text files manager extern char *DBGManager_GetFullSourceFilenameFromAdr(size_t Adr, bool *Error); -extern size_t DBGManager_GetNbFullSourceFilename(void); extern char *DBGManager_GetNumFullSourceFilename(size_t Index); +extern char *DBGManager_GetNumSourceFilename(size_t Index); // Global variables manager extern size_t DBGManager_GetNbGlobalVariables(void); diff --git a/src/debugger/DWARFManager.cpp b/src/debugger/DWARFManager.cpp index fed680a..b65227f 100644 --- a/src/debugger/DWARFManager.cpp +++ b/src/debugger/DWARFManager.cpp @@ -10,6 +10,7 @@ // JPM Dec./2016 Created this file, and added the DWARF format support // JPM Sept./2018 Added LEB128 decoding features, and improve the DWARF parsing information // JPM Oct./2018 Improve the DWARF parsing information, and the source file text reading; support the used source lines from DWARF structure, and the search paths for the files +// JPM Aug./2019 Added new functions to handle DWARF information, full filename fix // // To Do @@ -28,11 +29,14 @@ // Definitions for debugging -//#define DEBUG_NumCU 0x4d // CU number to debug or undefine it +//#define DEBUG_NumCU 0x44 // CU number to debug or undefine it //#define DEBUG_VariableName "sound_death" // Variable name to look for or undefine it //#define DEBUG_TypeName "Cbuf_Execute" // Type name to look for or undefine it //#define DEBUG_TypeDef DW_TAG_typedef // Type def to look for or undefine it (not supported) -//#define DEBUG_Filename "net_jag.c" // Filename to look for or undefine it +//#define DEBUG_Filename "crt0" // Filename to look for or undefine it + +// Definitions for handling data +//#define CONVERT_QT_HML // Text will be converted as HTML // Definitions for the variables's typetag #define TypeTag_structure 0x01 // structure @@ -125,6 +129,7 @@ typedef struct SubProgStruct typedef struct CUStruct { size_t Tag; + size_t Language; // Language (C, etc.) used by the source code size_t LowPC, HighPC; // Memory range for the code char *PtrProducer; // Pointer to the "Producer" text information (mostly compiler and compilation options used) char *PtrSourceFilename; // Source file name @@ -141,8 +146,11 @@ typedef struct CUStruct size_t NbVariables; // Variables number VariablesStruct *PtrVariables; // Pointer to the global variables list structure size_t NbFrames; // Frames number - size_t NbLinesSrc; // Number of used source lines - CUStruct_LineSrc *PtrLinesSrc; // Pointer to the used source lines list structure + size_t NbUsedLinesSrc; // Number of used source lines + size_t LastNumUsedLinesSrc; // Last used source number line + CUStruct_LineSrc *PtrUsedLinesSrc; // Pointer to the used source lines list structure + char **PtrUsedLinesLoadSrc; // Pointer lists to each used source line referenced by the CUStruct_LineSrc structure + size_t *PtrUsedNumLines; // Pointer list to the number lines used }S_CUStruct; @@ -167,6 +175,7 @@ void DWARFManager_InitInfosVariable(VariablesStruct *PtrVariables); void DWARFManager_SourceFileSearchPathsInit(void); void DWARFManager_SourceFileSearchPathsReset(void); void DWARFManager_SourceFileSearchPathsClose(void); +void DWARFManager_ConformSlachesBackslashes(char *Ptr); // @@ -278,7 +287,9 @@ void DWARFManager_CloseDMI(void) free(PtrCU[NbCU].PtrProducer); free(PtrCU[NbCU].PtrSourceFilename); free(PtrCU[NbCU].PtrSourceFileDirectory); - free(PtrCU[NbCU].PtrLinesSrc); + free(PtrCU[NbCU].PtrUsedLinesSrc); + free(PtrCU[NbCU].PtrUsedLinesLoadSrc); + free(PtrCU[NbCU].PtrUsedNumLines); while (PtrCU[NbCU].NbLinesLoadSrc--) { @@ -426,6 +437,14 @@ void DWARFManager_InitDMI(void) } break; + // Language + case DW_AT_language: + if (dwarf_formudata(atlist[i], &return_uvalue, &error) == DW_DLV_OK) + { + PtrCU[NbCU].Language = return_uvalue; + } + break; + default: break; } @@ -468,30 +487,29 @@ void DWARFManager_InitDMI(void) } } - // Create full filename - Ptr = PtrCU[NbCU].PtrFullFilename = (char *)realloc(PtrCU[NbCU].PtrFullFilename, strlen(PtrCU[NbCU].PtrSourceFilename) + strlen(PtrCU[NbCU].PtrSourceFileDirectory) + 2); -#if defined(_WIN32) - sprintf(PtrCU[NbCU].PtrFullFilename, "%s\\%s", PtrCU[NbCU].PtrSourceFileDirectory, PtrCU[NbCU].PtrSourceFilename); -#else - sprintf(PtrCU[NbCU].PtrFullFilename, "%s/%s", PtrCU[NbCU].PtrSourceFileDirectory, PtrCU[NbCU].PtrSourceFilename); -#endif - // Conform slashes and backslashes - while (*Ptr) + // Conform slashes / backslashes for the filename + DWARFManager_ConformSlachesBackslashes(PtrCU[NbCU].PtrSourceFilename); + + // Check if filename contains already the complete directory + if (PtrCU[NbCU].PtrSourceFilename[1] == ':') + { + // Copy the filename as the full filename + PtrCU[NbCU].PtrFullFilename = (char *)realloc(PtrCU[NbCU].PtrFullFilename, strlen(PtrCU[NbCU].PtrSourceFilename) + 1); + strcpy(PtrCU[NbCU].PtrFullFilename, PtrCU[NbCU].PtrSourceFilename); + } + else { + // Create full filename and Conform slashes / backslashes + PtrCU[NbCU].PtrFullFilename = (char *)realloc(PtrCU[NbCU].PtrFullFilename, strlen(PtrCU[NbCU].PtrSourceFilename) + strlen(PtrCU[NbCU].PtrSourceFileDirectory) + 2); #if defined(_WIN32) - if (*Ptr == '/') - { - *Ptr = '\\'; - } + sprintf(PtrCU[NbCU].PtrFullFilename, "%s\\%s", PtrCU[NbCU].PtrSourceFileDirectory, PtrCU[NbCU].PtrSourceFilename); #else - if (*Ptr == '\\') - { - *Ptr = '/'; - } + sprintf(PtrCU[NbCU].PtrFullFilename, "%s/%s", PtrCU[NbCU].PtrSourceFileDirectory, PtrCU[NbCU].PtrSourceFilename); #endif - Ptr++; } + DWARFManager_ConformSlachesBackslashes(PtrCU[NbCU].PtrFullFilename); + // Directory path clean-up #if defined(_WIN32) while ((Ptr1 = Ptr = strstr(PtrCU[NbCU].PtrFullFilename, "\\..\\"))) @@ -579,16 +597,26 @@ void DWARFManager_InitDMI(void) { if (cnt) { - PtrCU[NbCU].NbLinesSrc = cnt; - PtrCU[NbCU].PtrLinesSrc = (CUStruct_LineSrc *)calloc(cnt, sizeof(CUStruct_LineSrc)); + PtrCU[NbCU].NbUsedLinesSrc = cnt; + PtrCU[NbCU].PtrUsedLinesSrc = (CUStruct_LineSrc *)calloc(cnt, sizeof(CUStruct_LineSrc)); + PtrCU[NbCU].PtrUsedLinesLoadSrc = (char **)calloc(cnt, sizeof(char *)); + PtrCU[NbCU].PtrUsedNumLines = (size_t *)calloc(cnt, sizeof(size_t)); + + // Get the addresses and their source line numbers for (Dwarf_Signed i = 0; i < cnt; i++) { if (dwarf_lineaddr(linebuf[i], &return_lineaddr, &error) == DW_DLV_OK) { if (dwarf_lineno(linebuf[i], &return_uvalue, &error) == DW_DLV_OK) { - PtrCU[NbCU].PtrLinesSrc[i].StartPC = return_lineaddr; - PtrCU[NbCU].PtrLinesSrc[i].NumLineSrc = return_uvalue; + PtrCU[NbCU].PtrUsedLinesSrc[i].StartPC = return_lineaddr; + PtrCU[NbCU].PtrUsedLinesSrc[i].NumLineSrc = return_uvalue; + + // Get the last used line number in the source file + if (PtrCU[NbCU].LastNumUsedLinesSrc < PtrCU[NbCU].PtrUsedLinesSrc[i].NumLineSrc) + { + PtrCU[NbCU].LastNumUsedLinesSrc = PtrCU[NbCU].PtrUsedLinesSrc[i].NumLineSrc; + } } } } @@ -1041,6 +1069,7 @@ void DWARFManager_InitDMI(void) { switch (*Ptr) { +#ifdef CONVERT_QT_HML case 9: strcat(PtrCU[NbCU].PtrLinesLoadSrc[j], " "); i += 6; @@ -1066,6 +1095,7 @@ void DWARFManager_InitDMI(void) strcpy(PtrCU[NbCU].PtrLinesLoadSrc[j], """); i += strlen("""); break; +#endif #endif default: PtrCU[NbCU].PtrLinesLoadSrc[j][i++] = *Ptr; @@ -1117,23 +1147,28 @@ void DWARFManager_InitDMI(void) } } - // Set information based on used line numbers - if (PtrCU[NbCU].PtrLinesSrc) + // Check validity between used number lines and number lines in the source file + if (PtrCU[NbCU].LastNumUsedLinesSrc <= PtrCU[NbCU].NbLinesLoadSrc) { - // Set the line source pointer for each used line numbers - if (PtrCU[NbCU].PtrLinesLoadSrc) + // Set information based on used line numbers + if (PtrCU[NbCU].PtrUsedLinesSrc) { - for (size_t i = 0; i < PtrCU[NbCU].NbLinesSrc; i++) + // Set the line source pointers for each used line numbers + if (PtrCU[NbCU].PtrLinesLoadSrc) { - PtrCU[NbCU].PtrLinesSrc[i].PtrLineSrc = PtrCU[NbCU].PtrLinesLoadSrc[PtrCU[NbCU].PtrLinesSrc[i].NumLineSrc - 1]; - } + for (size_t i = 0; i < PtrCU[NbCU].NbUsedLinesSrc; i++) + { + PtrCU[NbCU].PtrUsedNumLines[i] = PtrCU[NbCU].PtrUsedLinesSrc[i].NumLineSrc - 1; + PtrCU[NbCU].PtrUsedLinesLoadSrc[i] = PtrCU[NbCU].PtrUsedLinesSrc[i].PtrLineSrc = PtrCU[NbCU].PtrLinesLoadSrc[PtrCU[NbCU].PtrUsedLinesSrc[i].NumLineSrc - 1]; + } - // Setup memory range for the code if CU doesn't have already this information - // It is taken from the used lines structure - if (!PtrCU[NbCU].LowPC && (!PtrCU[NbCU].HighPC || (PtrCU[NbCU].HighPC == ~0))) - { - PtrCU[NbCU].LowPC = PtrCU[NbCU].PtrLinesSrc[0].StartPC; - PtrCU[NbCU].HighPC = PtrCU[NbCU].PtrLinesSrc[PtrCU[NbCU].NbLinesSrc - 1].StartPC; + // Setup memory range for the code if CU doesn't have already this information + // It is taken from the used lines structure + if (!PtrCU[NbCU].LowPC && (!PtrCU[NbCU].HighPC || (PtrCU[NbCU].HighPC == ~0))) + { + PtrCU[NbCU].LowPC = PtrCU[NbCU].PtrUsedLinesSrc[0].StartPC; + PtrCU[NbCU].HighPC = PtrCU[NbCU].PtrUsedLinesSrc[PtrCU[NbCU].NbUsedLinesSrc - 1].StartPC; + } } } } @@ -1160,6 +1195,27 @@ void DWARFManager_InitDMI(void) } +// Conform slashes and backslashes +void DWARFManager_ConformSlachesBackslashes(char *Ptr) +{ + while (*Ptr) + { +#if defined(_WIN32) + if (*Ptr == '/') + { + *Ptr = '\\'; + } +#else + if (*Ptr == '\\') + { + *Ptr = '/'; + } +#endif + Ptr++; + } +} + + // Variables information initialisation void DWARFManager_InitInfosVariable(VariablesStruct *PtrVariables) { @@ -1803,11 +1859,11 @@ size_t DWARFManager_GetNumLineFromAdr(size_t Adr, size_t Tag) } // Check if a used line is found with the address - for (size_t j = 0; j < PtrCU[i].NbLinesSrc; j++) + for (size_t j = 0; j < PtrCU[i].NbUsedLinesSrc; j++) { - if (PtrCU[i].PtrLinesSrc[j].StartPC == Adr) + if (PtrCU[i].PtrUsedLinesSrc[j].StartPC == Adr) { - return PtrCU[i].PtrLinesSrc[j].NumLineSrc; + return PtrCU[i].PtrUsedLinesSrc[j].NumLineSrc; } } } @@ -1839,6 +1895,57 @@ char *DWARFManager_GetFunctionName(size_t Adr) } +// Get number of lines of texts source list from source index +size_t DWARFManager_GetSrcNbListPtrFromIndex(size_t Index, bool Used) +{ + if (!Used) + { + return PtrCU[Index].NbLinesLoadSrc; + } + else + { + return PtrCU[Index].NbUsedLinesSrc; + } +} + + +// Get text source line number list pointer from source index +// Return NULL for the text source used list +size_t *DWARFManager_GetSrcNumLinesPtrFromIndex(size_t Index, bool Used) +{ + if (Used) + { + return PtrCU[Index].PtrUsedNumLines; + } + else + { + return NULL; + } +} + + +// Get text source list pointers from source index +// Return NULL for the text source used list +char **DWARFManager_GetSrcListPtrFromIndex(size_t Index, bool Used) +{ + if (!Used) + { + return PtrCU[Index].PtrLinesLoadSrc; + } + else + { + return PtrCU[Index].PtrUsedLinesLoadSrc; + } +} + + +// Get source language +size_t DWARFManager_GetSrcLanguageFromIndex(size_t Index) +{ + return PtrCU[Index].Language; +} + + // Get text line from source based on address and num line (starting from 1) // Return NULL if no text line has been found char *DWARFManager_GetLineSrcFromAdrNumLine(size_t Adr, size_t NumLine) @@ -1898,15 +2005,22 @@ char *DWARFManager_GetLineSrcFromNumLineBaseAdr(size_t Adr, size_t NumLine) // Get number of source code filenames -size_t DWARFManager_GetNbFullSourceFilename(void) +size_t DWARFManager_GetNbSources(void) { return NbCU; } -// Get source code filename based on index (starting from 0) +// Get source code filename, including his directory, based on index (starting from 0) char *DWARFManager_GetNumFullSourceFilename(size_t Index) { return (PtrCU[Index].PtrFullFilename); } + +// Get source code filename based on index (starting from 0) +char *DWARFManager_GetNumSourceFilename(size_t Index) +{ + return (PtrCU[Index].PtrSourceFilename); +} + diff --git a/src/debugger/DWARFManager.h b/src/debugger/DWARFManager.h index d05e4ee..9df4535 100644 --- a/src/debugger/DWARFManager.h +++ b/src/debugger/DWARFManager.h @@ -10,14 +10,16 @@ extern bool DWARFManager_Close(void); extern void DWARFManager_Init(void); extern int DWARFManager_ElfInit(Elf *ElfPtr); extern void DWARFManager_Set(size_t NbPathsInList, char **PtrListPaths); +extern size_t DWARFManager_GetNbSources(void); // General manager extern char *DWARFManager_GetFunctionName(size_t Adr); +extern size_t DWARFManager_GetSrcLanguageFromIndex(size_t Index); // Source text files manager extern char *DWARFManager_GetFullSourceFilenameFromAdr(size_t Adr, bool *Error); -extern size_t DWARFManager_GetNbFullSourceFilename(void); extern char *DWARFManager_GetNumFullSourceFilename(size_t Index); +extern char *DWARFManager_GetNumSourceFilename(size_t Index); // Symbols manager extern char *DWARFManager_GetSymbolnameFromAdr(size_t Adr); @@ -27,6 +29,9 @@ extern size_t DWARFManager_GetNumLineFromAdr(size_t Adr, size_t Tag); extern char *DWARFManager_GetLineSrcFromAdr(size_t Adr, size_t Tag); extern char *DWARFManager_GetLineSrcFromAdrNumLine(size_t Adr, size_t NumLine); extern char *DWARFManager_GetLineSrcFromNumLineBaseAdr(size_t Adr, size_t NumLine); +extern char **DWARFManager_GetSrcListPtrFromIndex(size_t Index, bool Used); +extern size_t DWARFManager_GetSrcNbListPtrFromIndex(size_t Index, bool Used); +extern size_t *DWARFManager_GetSrcNumLinesPtrFromIndex(size_t Index, bool Used); // Global variables manager extern size_t DWARFManager_GetNbGlobalVariables(void); diff --git a/src/debugger/FilesrcListWin.cpp b/src/debugger/FilesrcListWin.cpp index ab0fb9c..5017db0 100644 --- a/src/debugger/FilesrcListWin.cpp +++ b/src/debugger/FilesrcListWin.cpp @@ -104,7 +104,7 @@ size_t FilesrcListWindow::UpdateInfos(void) { size_t Nbr, i; - Nbr = DBGManager_GetNbFullSourceFilename(); + Nbr = DBGManager_GetNbSources(); for (i = 0; i < Nbr; i++) { diff --git a/src/debugger/SourceCWin.cpp b/src/debugger/SourceCWin.cpp new file mode 100644 index 0000000..a69edc2 --- /dev/null +++ b/src/debugger/SourceCWin.cpp @@ -0,0 +1,195 @@ +// +// SourceCWin.cpp - Source C tracing window +// +// by Jean-Paul Mari +// +// JPM = Jean-Paul Mari +// +// Who When What +// --- ---------- ------------------------------------------------------------- +// JPM 08/23/2019 Created this file + +// STILL TO DO: +// + +#include +#include "DBGManager.h" +#include "debugger/SourceCWin.h" +#include "debugger/SourcesWin.h" +//#include "m68000/m68kinterface.h" + + +// +SourceCWindow::SourceCWindow(QWidget * parent/*= 0*/) : QWidget(parent, Qt::Dialog), +layout(new QVBoxLayout), +FileIndex(0), +CurrentNumLineSrc(0), +#ifdef SC_LAYOUTTEXTS +text(new QTextBrowser) +#else +TableView(new QTableView), +model(new QStandardItemModel) +#endif +{ + // Set font + QFont fixedFont("Lucida Console", 8, QFont::Normal); + fixedFont.setStyleHint(QFont::Monospace); //TypeWriter + fixedFont.setLetterSpacing(QFont::PercentageSpacing, 100); + + // Set text in layout +#ifdef SC_LAYOUTTEXTS + text->setFont(fixedFont); + layout->addWidget(text); +#else + // Set the new layout with proper identation and readibility + model->setColumnCount(3); + model->setHeaderData(0, Qt::Horizontal, QObject::tr("LineStatus")); + model->setHeaderData(1, Qt::Horizontal, QObject::tr("LineNumber")); + model->setHeaderData(2, Qt::Horizontal, QObject::tr("LineSrc")); + // Information table + TableView->setModel(model); + TableView->setEditTriggers(QAbstractItemView::NoEditTriggers); + TableView->setSelectionMode(QAbstractItemView::NoSelection); + TableView->setShowGrid(false); + TableView->horizontalHeader()->hide(); + TableView->verticalHeader()->hide(); + TableView->setFont(fixedFont); + layout->addWidget(TableView); +#endif + + // Set layout + setLayout(layout); +} + + +// +void SourceCWindow::SetCursorTrace(int NumLineSrc, bool Remove) +{ + // Check valid line number + if (NumLineSrc && (NbLinesText[0] >= NumLineSrc)) + { + // Set the trace cursor + if (!Remove) + { + CurrentNumLineSrc = NumLineSrc; +#ifndef SC_LAYOUTTEXTS + model->item((NumLineSrc - 1), 0)->setText(">"); + model->item((NumLineSrc - 1), 0)->setBackground(QColor(0xff, 0xfa, 0xcd)); + model->item((NumLineSrc - 1), 1)->setBackground(QColor(0xff, 0xfa, 0xcd)); + model->item((NumLineSrc - 1), 2)->setBackground(QColor(0xff, 0xfa, 0xcd)); +#endif + } + else + { + // Remove the trace cursor +#ifndef SC_LAYOUTTEXTS + model->item((NumLineSrc - 1), 0)->setText(" "); + model->item((NumLineSrc - 1), 0)->setBackground(QColor(173, 216, 230)); + model->item((NumLineSrc - 1), 1)->setBackground(QColor(255, 255, 255)); + model->item((NumLineSrc - 1), 2)->setBackground(QColor(255, 255, 255)); +#endif + } + } +} + + +// +void SourceCWindow::RefreshContents(void) +{ + if (isVisible()) + { + // Get the scroll bar information + int MaxSlider = TableView->verticalScrollBar()->maximum(); // Get the slider maximum position + int DeltaSlider = (int)NbLinesText[0] - MaxSlider; // Number of items displayed in the scroll bar slider + //int PosSlider = TableView->verticalScrollBar()->sliderPosition(); // Slider position + + // Check visibility in the scroll bar + //if ((CurrentNumLineSrc > PosSlider) && ((CurrentNumLineSrc + (DeltaSlider / 2)) < MaxSlider)) + { + // Set the scroll bar position + TableView->verticalScrollBar()->setSliderPosition(CurrentNumLineSrc - (DeltaSlider / 2) - 1); + } + } +} + + +// Fill the tab with the source text +void SourceCWindow::FillTab(size_t index, char **TextLines, size_t NbLines[], size_t *NumLinesUsed) +{ + int i, j, k; +#ifdef SC_LAYOUTTEXTS + QString s; + char string[1024]; +#endif + + // Save information + FileIndex = index; + for (i = 0; i < 2; i++) + { + NbLinesText[i] = NbLines[i]; + } + PtrTextLines = TextLines; + PtrNumLinesUsed = NumLinesUsed; + + // Set columns +#ifndef SC_LAYOUTTEXTS + model->insertRow((int)NbLinesText[0]); +#endif + + // Set text lines + for (i = j = 0; i < NbLinesText[0]; i++, j = 0) + { + // prepare space for the line status +#ifndef SC_LAYOUTTEXTS + model->setItem(i, 0, new QStandardItem(QString("%1").arg(" "))); + model->item(i, 0)->setTextAlignment(Qt::AlignCenter); + model->item(i, 0)->setBackground(QColor(173, 216, 230)); +#endif + // display line number +#ifdef SC_LAYOUTTEXTS + sprintf(string, "| %5u | ", (i + 1)); + s += QString(string); +#else + model->setItem(i, 1, new QStandardItem(QString(" %1 ").arg((i + 1)))); + model->item(i, 1)->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter); + model->item(i, 1)->setForeground(QColor(0, 0x64, 0)); +#endif + // display source code line +#ifndef SC_LAYOUTTEXTS + model->setItem(i, 2, new QStandardItem(QString("%1").arg(PtrTextLines[i]))); + model->item(i, 2)->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter); +#endif + // Check line used by code + while ((j < NbLinesText[1]) && !(k = ((PtrNumLinesUsed[j++] != i) - 1))); + if (k) + { + // Line is used by code +#ifdef SC_LAYOUTTEXTS + sprintf(string, "%s", PtrTextLines[i]); +#else + model->item(i, 2)->setForeground(QColor(0, 0, 0)); +#endif + } + else + { + // Line is not used by code (such as comments) +#ifdef SC_LAYOUTTEXTS + sprintf(string, "%s", PtrTextLines[i]); +#else + model->item(i, 2)->setForeground(QColor(0xc8, 0xc8, 0xc8)); +#endif + } +#ifdef SC_LAYOUTTEXTS + s += QString(string); + s += QString("
"); +#endif + } + + // Display text +#ifdef SC_LAYOUTTEXTS + text->setText(s); +#else + TableView->resizeColumnsToContents(); + TableView->resizeRowsToContents(); +#endif +} diff --git a/src/debugger/SourceCWin.h b/src/debugger/SourceCWin.h new file mode 100644 index 0000000..5f39233 --- /dev/null +++ b/src/debugger/SourceCWin.h @@ -0,0 +1,49 @@ +// +// SourcesWin.h: Source C tracing window +// +// JPM = Jean-Paul Mari +// +// Who When What +// --- ---------- ------------------------------------------------------------- +// JPM 08/23/2019 Created this file +// + +#ifndef __SOURCECWIN_H__ +#define __SOURCECWIN_H__ + +//#define SC_LAYOUTTEXTS // Use a layout with just texts + +#include +//#include + + +class SourceCWindow : public QWidget +{ + Q_OBJECT + +public: + SourceCWindow(QWidget * parent = 0); + void FillTab(size_t index, char **TextLines, size_t NbLines[], size_t *NumLinesUsed); + void SetCursorTrace(int NumLineSrc, bool Remove); + +public slots: + void RefreshContents(void); + +protected: + +private: + size_t FileIndex; + int CurrentNumLineSrc; + QVBoxLayout *layout; +#ifdef SC_LAYOUTTEXTS + QTextBrowser *text; +#else + QTableView *TableView; + QStandardItemModel *model; +#endif + char **PtrTextLines; + size_t NbLinesText[2]; + size_t *PtrNumLinesUsed; +}; + +#endif diff --git a/src/debugger/SourcesWin.cpp b/src/debugger/SourcesWin.cpp new file mode 100644 index 0000000..0dfa87e --- /dev/null +++ b/src/debugger/SourcesWin.cpp @@ -0,0 +1,263 @@ +// +// SourcesWin.cpp - Sources tracing window +// +// by Jean-Paul Mari +// +// JPM = Jean-Paul Mari +// +// Who When What +// --- ---------- ------------------------------------------------------------- +// JPM 08/23/2019 Created this file + +// STILL TO DO: +// + +#include +#include +#include "DBGManager.h" +#include "debugger/SourceCWin.h" +#include "debugger/SourcesWin.h" +#include "m68000/m68kinterface.h" + + +// +SourcesWindow::SourcesWindow(QWidget * parent/*= 0*/) : QWidget(parent, Qt::Dialog), +layout(new QVBoxLayout), +sourcestabWidget(new QTabWidget), +sourcesinfostab(0), +NbSourcesInfos(0), +CurrentTab(0), +OldCurrentTab(0), +OldCurrentNumLineSrc(0), +indexErrorTab(-1), +sourceErrorTab(0) +{ + // Prepare layout + sourcestabWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + sourcestabWidget->setTabsClosable(true); + layout->addWidget(sourcestabWidget); + + // Set layout + setLayout(layout); + + // Connect the signals + connect(sourcestabWidget, SIGNAL(currentChanged(const int)), this, SLOT(SelectTab(const int))); + connect(sourcestabWidget, SIGNAL(tabCloseRequested(const int)), this, SLOT(CloseTab(const int))); +} + + +// Close tab +void SourcesWindow::CloseTab(const int) +{ + CloseCurrentTab(); +} + + +// Select tab +void SourcesWindow::SelectTab(const int) +{ +#if 0 + size_t i = 0; + QString t = sourcestabWidget->tabText(index); + while ((i < NbSourcesInfos) && strcmp(sourcesinfostab[i++].Filename, t.toLatin1().data())); + + if ((i != NbSourcesInfos) && (sourcesinfostab[i - 1].IndexTab != -1) && (CurrentTab == (i - 1))) + { + sourcesinfostab[(i - 1)].sourceCtab->RefreshContents(); + } +#endif +} + + +// Sources initialisation +void SourcesWindow::Init(void) +{ + size_t i, j; + char *Ptr, *Ptr1; + + // Get number of sources + NbSourcesInfos = DBGManager_GetNbSources(); + if (NbSourcesInfos) + { + // Alloc structure for the source informations + sourcesinfostab = (SourcesInfos *)calloc(NbSourcesInfos, sizeof(SourcesInfos)); + + // Fill sources information + for (i = 0; i < NbSourcesInfos; i++) + { + // Get source filename without misguiding information + Ptr = DBGManager_GetNumSourceFilename(i); + Ptr1 = sourcesinfostab[i].Filename = (char *)malloc(strlen(Ptr) + 1); + while (((*Ptr == '.') || ((*Ptr == '/') || (*Ptr == '\\'))) && Ptr++); + strcpy(Ptr1, Ptr); + // Get texts dedicated information + for (j = 0; j < 2; j++) + { + sourcesinfostab[i].NbLinesText[j] = DBGManager_GetSrcNbListPtrFromIndex(i, j); + } + sourcesinfostab[i].NumLinesUsed = DBGManager_GetSrcNumLinesPtrFromIndex(i, true); + sourcesinfostab[i].SourceText = DBGManager_GetSrcListPtrFromIndex(i, false); + // Get remaining information + sourcesinfostab[i].Language = DBGManager_GetSrcLanguageFromIndex(i); + sourcesinfostab[i].IndexTab = -1; + } + } +} + + +// Get the tracing status +bool SourcesWindow::GetTraceStatus(void) +{ + if (NbSourcesInfos) + { + switch (sourcesinfostab[CurrentTab].Language) + { + case DBG_LANG_VASM_Assembler: + break; + + default: + return true; + break; + } + } + + return false; +} + + +// Check if line has changed +bool SourcesWindow::CheckChangeLine(void) +{ + size_t NumLine; + + if (NumLine = DBGManager_GetNumLineFromAdr(m68k_get_reg(NULL, M68K_REG_PC), DBG_NO_TAG)) + { + if (OldCurrentTab == CurrentTab) + { + if (OldCurrentNumLineSrc != NumLine) + { + OldCurrentNumLineSrc = NumLine; + return true; + } + } + else + { + OldCurrentTab = CurrentTab; + OldCurrentNumLineSrc = 0; + } + + } + + return false; +} + + +// +void SourcesWindow::RefreshContents(void) +{ + size_t m68kPC = m68k_get_reg(NULL, M68K_REG_PC); + int index = 0; + size_t i; + bool Error; + char *Filename; + + // Check valid PC + if (m68kPC && NbSourcesInfos) + { + // Get source filename pointed by PC address + Filename = DBGManager_GetFullSourceFilenameFromAdr(m68kPC, &Error); + if (Error && Filename) + { + // Look for a new tab + for (i = 0; i < NbSourcesInfos; i++, !index) + { + if (sourcesinfostab[i].Filename) + { + if (strstr(Filename, sourcesinfostab[i].Filename)) + { + // Open a new tab for a source code + if (sourcesinfostab[i].IndexTab == -1) + { + sourcesinfostab[i].IndexTab = index = sourcestabWidget->addTab(sourcesinfostab[i].sourceCtab = new(SourceCWindow), tr(sourcesinfostab[i].Filename)); + sourcesinfostab[i].sourceCtab->FillTab(i, sourcesinfostab[i].SourceText, sourcesinfostab[i].NbLinesText, sourcesinfostab[i].NumLinesUsed); + } + + sourcestabWidget->setCurrentIndex(sourcesinfostab[i].IndexTab); + sourcesinfostab[CurrentTab].sourceCtab->SetCursorTrace(sourcesinfostab[CurrentTab].CurrentNumLineSrc, true); + sourcesinfostab[i].sourceCtab->SetCursorTrace(sourcesinfostab[i].CurrentNumLineSrc = (int)DBGManager_GetNumLineFromAdr(m68kPC, DBG_NO_TAG), false); + sourcesinfostab[i].sourceCtab->RefreshContents(); + CurrentTab = i; + } + } + } + } + else + { + // Source file doesn't exist + if (indexErrorTab == -1) + { + indexErrorTab = sourcestabWidget->addTab(sourceErrorTab = new(SourceCWindow), tr("Source file not found")); + //sourceErrorTab->hide(); + } + sourcestabWidget->setCurrentIndex(indexErrorTab); + } + } +} + + +// Close / Remove current tab +void SourcesWindow::CloseCurrentTab(void) +{ + size_t i = 0; + int Index; + QString t = sourcestabWidget->tabText((Index = sourcestabWidget->currentIndex())); + + // Check error tab presence + if (indexErrorTab == Index) + { + // Close the error tab + indexErrorTab = -1; + } + else + { + // Close source code text tab + while ((i < NbSourcesInfos) && strcmp(sourcesinfostab[i++].Filename, t.toLatin1().data())); + sourcesinfostab[(i - 1)].IndexTab = -1; + } + + // remove the tab + sourcestabWidget->removeTab(Index); +} + + +// +void SourcesWindow::keyPressEvent(QKeyEvent * e) +{ + // Close/Remove the current tab + if (e->key() == Qt::Key_Escape) + { + CloseCurrentTab(); + } +} + + +// +void SourcesWindow::Reset(void) +{ + // Clear the tabs + sourcestabWidget->clear(); + + // Clear tab information + while (NbSourcesInfos) + { + free(sourcesinfostab[--NbSourcesInfos].Filename); + } + free(sourcesinfostab); +} + + +// +void SourcesWindow::Close(void) +{ + Reset(); +} diff --git a/src/debugger/SourcesWin.h b/src/debugger/SourcesWin.h new file mode 100644 index 0000000..300c58c --- /dev/null +++ b/src/debugger/SourcesWin.h @@ -0,0 +1,65 @@ +// +// SourcesWin.h: Sources tracing window +// +// JPM = Jean-Paul Mari +// +// Who When What +// --- ---------- ------------------------------------------------------------- +// JPM 08/23/2019 Created this file +// + +#ifndef __SOURCESWIN_H__ +#define __SOURCESWIN_H__ + +#include +//#include + +class SourceCWindow; + +class SourcesWindow : public QWidget +{ + Q_OBJECT + + typedef struct S_SOURCESINFOS + { + int IndexTab; + char *Filename; + char **SourceText; + size_t NbLinesText[2]; + size_t *NumLinesUsed; + size_t Language; + SourceCWindow *sourceCtab; + int CurrentNumLineSrc; + } + SourcesInfos; + +public: + SourcesWindow(QWidget * parent = 0); + void Init(void); + void Close(void); + void Reset(void); + bool GetTraceStatus(void); + bool CheckChangeLine(void); + +public slots: + void RefreshContents(void); + void SelectTab(const int); + void CloseTab(const int); + +protected: + void keyPressEvent(QKeyEvent * e); + void CloseCurrentTab(void); + +private: + QVBoxLayout *layout; + QTabWidget *sourcestabWidget; + SourcesInfos *sourcesinfostab; + size_t NbSourcesInfos; + size_t CurrentTab; + size_t OldCurrentNumLineSrc; + size_t OldCurrentTab; + int indexErrorTab; + SourceCWindow *sourceErrorTab; +}; + +#endif // __SOURCESWIN_H__ diff --git a/src/gui/mainwin.cpp b/src/gui/mainwin.cpp index 98f1df8..ede2dc8 100644 --- a/src/gui/mainwin.cpp +++ b/src/gui/mainwin.cpp @@ -23,7 +23,7 @@ // JPM Oct./2018 Added search paths in the settings, breakpoints feature, cartridge view menu // JPM 11/18/2018 Fix crash with non-debugger mode // JPM April/2019 Added ELF sections check, added a save memory dump -// JPM Aug./2019 Update texts descriptions, set cartridge view menu for debugger mode only, added a HW registers browser +// JPM Aug./2019 Update texts descriptions, set cartridge view menu for debugger mode only, added a HW registers browser and source level tracing // // FIXED: @@ -36,10 +36,10 @@ // // STILL TO BE DONE: // +// - The source file listing do not need to be refresh more than one time // - Fix bug in switching between PAL & NTSC in fullscreen mode. // - Remove SDL dependencies (sound, mainly) from Jaguar core lib -// - Fix inconsistency with trailing slashes in paths (eeproms needs one, -// software doesn't) +// - Fix inconsistency with trailing slashes in paths (eeproms needs one, software doesn't) // // SFDX CODE: S1E9T8H5M23YS @@ -91,6 +91,7 @@ #include "debugger/DBGManager.h" //#include "debugger/VideoWin.h" //#include "debugger/DasmWin.h" +#include "debugger/SourcesWin.h" #include "debugger/m68KDasmWin.h" #include "debugger/GPUDasmWin.h" #include "debugger/DSPDasmWin.h" @@ -244,9 +245,11 @@ MainWin::MainWin(bool autoRun): running(true), powerButtonOn(false), #endif // Setup disasm tabs dasmtabWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - dasmtabWidget->addTab(m68kDasmWin = new m68KDasmWindow(this), tr("M68000")); + dasmtabWidget->addTab(SourcesWin = new SourcesWindow(this), tr("Sources")); + dasmtabWidget->setCurrentIndex(dasmtabWidget->addTab(m68kDasmWin = new m68KDasmWindow(this), tr("M68000"))); dasmtabWidget->addTab(GPUDasmWin = new GPUDasmWindow(this), tr("GPU")); dasmtabWidget->addTab(DSPDasmWin = new DSPDasmWindow(this), tr("DSP")); + connect(dasmtabWidget, SIGNAL(currentChanged(const int)), this, SLOT(SelectdasmtabWidget(const int))); #if 1 setCentralWidget(dasmtabWidget); #endif @@ -858,6 +861,17 @@ void MainWin::SyncUI(void) } +// +void MainWin::SelectdasmtabWidget(const int Index) +{ + // check sources tab + if (Index == 0) + { + SourcesWin->RefreshContents(); + } +} + + void MainWin::closeEvent(QCloseEvent * event) { JaguarDone(); @@ -1480,6 +1494,7 @@ void MainWin::LoadSoftware(QString file) { m68k_set_reg(M68K_REG_A6, 0); m68kDasmWin->SetAddress(jaguarRunAddress); + SourcesWin->Init(); //pauseAct->setDisabled(false); //pauseAct->setChecked(true); ToggleRunState(); @@ -1567,7 +1582,18 @@ void MainWin::ShowSaveDumpAsWin(void) // Step Into trace void MainWin::DebuggerTraceStepInto(void) { - JaguarStepInto(); + if (SourcesWin->isVisible() && SourcesWin->GetTraceStatus()) + { + while (!SourcesWin->CheckChangeLine()) + { + JaguarStepInto(); + } + } + else + { + JaguarStepInto(); + } + videoWidget->updateGL(); RefreshWindows(); #ifdef _MSC_VER @@ -1587,11 +1613,13 @@ void MainWin::DebuggerRestart(void) m68k_set_reg(M68K_REG_PC, jaguarRunAddress); m68k_set_reg(M68K_REG_SP, vjs.DRAM_size); #endif + dasmtabWidget->setCurrentIndex(1); // set focus on the disasm M68K tab m68k_set_reg(M68K_REG_A6, 0); m68k_brk_hitcounts_reset(); bpmHitCounts = 0; DebuggerResetWindows(); CommonResetWindows(); + SourcesWin->Init(); RefreshWindows(); #ifdef _MSC_VER #pragma message("Warning: !!! Need to verify the Restart function !!!") @@ -1604,7 +1632,15 @@ void MainWin::DebuggerRestart(void) // Step Over trace void MainWin::DebuggerTraceStepOver(void) { - JaguarStepOver(0); + if (SourcesWin->isVisible() && SourcesWin->GetTraceStatus()) + { + + } + else + { + JaguarStepOver(0); + } + videoWidget->updateGL(); RefreshWindows(); #ifdef _MSC_VER @@ -2423,6 +2459,7 @@ void MainWin::DebuggerResetWindows(void) heapallocatorBrowseWin->Reset(); BreakpointsWin->Reset(); CartFilesListWin->Reset(); + SourcesWin->Reset(); //ResetAlpineWindows(); } } @@ -2456,6 +2493,7 @@ void MainWin::DebuggerRefreshWindows(void) if (vjs.softTypeDebugger) { FilesrcListWin->RefreshContents(); + SourcesWin->RefreshContents(); m68kDasmWin->RefreshContents(); GPUDasmWin->RefreshContents(); DSPDasmWin->RefreshContents(); diff --git a/src/gui/mainwin.h b/src/gui/mainwin.h index 466c2a4..8ac4058 100644 --- a/src/gui/mainwin.h +++ b/src/gui/mainwin.h @@ -36,6 +36,7 @@ class RISCDasmBrowserWindow; class HWRegsBrowserWindow; // Debugger +class SourcesWindow; class m68KDasmWindow; class GPUDasmWindow; class DSPDasmWindow; @@ -115,6 +116,7 @@ class MainWin: public QMainWindow void DeleteAllBreakpoints(void); void DisableAllBreakpoints(void); void ShowSaveDumpAsWin(void); + void SelectdasmtabWidget(const int); #if 0 void ShowVideoOutputWin(void); void ShowDasmWin(void); @@ -164,6 +166,7 @@ class MainWin: public QMainWindow //DasmWindow * DasmWin; QTabWidget *dasmtabWidget; //QDockWidget *dasmtabWidget; + SourcesWindow *SourcesWin; m68KDasmWindow *m68kDasmWin; GPUDasmWindow *GPUDasmWin; DSPDasmWindow *DSPDasmWin; diff --git a/virtualjaguar.pro b/virtualjaguar.pro index 515223c..fa4be73 100644 --- a/virtualjaguar.pro +++ b/virtualjaguar.pro @@ -111,6 +111,8 @@ HEADERS = \ src/debugger/debuggertab.h \ src/debugger/DasmWin.h \ src/debugger/m68kDasmWin.h \ + src/debugger/SourcesWin.h \ + src/debugger/SourceCWin.h \ src/debugger/DBGManager.h \ src/debugger/DSPDasmWin.h \ src/debugger/GPUDasmWin.h \ @@ -167,6 +169,8 @@ SOURCES = \ src/debugger/debuggertab.cpp \ src/debugger/DasmWin.cpp \ src/debugger/m68kDasmWin.cpp \ + src/debugger/SourcesWin.cpp \ + src/debugger/SourceCWin.cpp \ src/debugger/DBGManager.cpp \ src/debugger/DSPDasmWin.cpp \ src/debugger/GPUDasmWin.cpp \