7 #define GDB_DEBUG_CONSOLE
10 extern char * strrchr(const char * s, int c);
13 #define strlen _strlen
23 #include <sys/time.h> // Required on Apple...
28 public char * StripQuotes2(char * string, char * output)
32 bool quoted = false, escaped = false;
34 for(c = 0; ch = string[c]; c++)
38 if(escaped || ch != '\"')
41 escaped = !escaped && ch == '\\';
56 static void strescpy(char * d, char * s)
109 static char * CopyUnescapedSystemPath(char * p)
111 char * d = new char[strlen(p) + 1];
113 #if defined(__WIN32__)
114 ChangeCh(d, '/', '\\');
119 static char * CopyUnescapedUnixPath(char * p)
121 char * d = new char[strlen(p) + 1];
123 #if defined(__WIN32__)
124 ChangeCh(d, '\\', '/');
129 static char * CopyUnescapedString(char * s)
131 char * d = new char[strlen(s) + 1];
136 // String Unescape Copy
138 // TOFIX: THIS DOESN'T HANDLE NUMERIC ESCAPE CODES (OCTAL/HEXADECIMAL...)?
139 // Seems very similar to ReadString in pass15.ec (which also misses numeric escape codes :) )
141 static void struscpy(char * d, char * s)
193 static char * StripBrackets(char * string)
195 int length = strlen(string);
196 if(length > 1 && *string == '[' && string[length - 1] == ']')
199 string[length - 1] = '\0';
206 static char * StripCurlies(char * string)
208 int length = strlen(string);
209 if(length > 1 && *string == '{' && string[length - 1] == '}')
212 string[length - 1] = '\0';
219 static int StringGetInt(char * string, int start)
222 int i, len = strlen(string);
224 for(i = start; i < len && i < start + 8; i++)
226 if(string[i] == '0' || string[i] == '1' || string[i] == '2' || string[i] == '3' || string[i] == '4' || string[i] == '5' || string[i] == '6' || string[i] == '7' || string[i] == '8' || string[i] == '9')
227 strncat(number, &string[i], 1);
234 static int TokenizeList(char * string, const char seperator, Array<char *> tokens)
238 bool quoted = false, escaped = false;
239 char * start = string, ch;
241 for(; (ch = *string); string++)
248 if(escaped || ch != '\"')
249 escaped = !escaped && ch == '\\';
255 else if(ch == '{' || ch == '[' || ch == '(' || ch == '<')
257 else if(ch == '}' || ch == ']' || ch == ')' || ch == '>')
259 else if(ch == seperator && !level)
268 //tokens[count] = start;
269 //tokens[count++] = start;
276 static bool TokenizeListItem(char * string, DebugListItem item)
278 char * equal = strstr(string, "=");
292 static void DebuggerProtocolUnknown(char * message, char * gdbOutput)
294 #ifdef _DEBUG_GDB_PROTOCOL
295 ide.outputView.debugBox.Logf("Debugger Protocol Error: %s (%s)\n", message, gdbOutput);
299 // define GdbGetLineSize = 1638400;
300 define GdbGetLineSize = 5638400;
301 #if defined(__unix__)
302 char progFifoPath[MAX_LOCATION];
303 char progFifoDir[MAX_LOCATION];
306 enum DebuggerState { none, prompt, loaded, running, stopped, terminated };
307 enum DebuggerEvent { none, hit, breakEvent, signal, stepEnd, functionEnd, exit };
308 enum DebuggerAction { none, internal, restart, stop, selectFrame }; //, bpValidation
309 enum BreakpointType { none, internalMain, internalWinMain, internalModulesLoaded, user, runToCursor, internalModuleLoad };
310 enum DebuggerEvaluationError { none, symbolNotFound, memoryCantBeRead, unknown };
312 FileDialog debuggerFileDialog { type = selectDir };
314 static DualPipe gdbHandle;
315 static DebugEvaluationData eval { };
317 static int targetProcessId;
319 static bool gdbReady;
320 static bool breakpointError;
324 Semaphore serialSemaphore { };
329 //bool breakpointsInserted;
331 bool sentBreakInsert;
332 bool ignoreBreakpoints;
333 bool userBreakOnInternBreak;
340 int activeFrameLevel;
351 DebuggerAction breakType;
352 //DebuggerCommand lastCommand; // THE COMPILER COMPILES STUFF THAT DOES NOT EXIST???
354 GdbDataStop stopItem;
355 GdbDataBreakpoint bpItem;
358 List<Breakpoint> sysBPs { };
359 Breakpoint bpRunToCursor;
365 CompilerConfig currentCompiler;
366 ProjectConfig prjConfig;
369 CodeEditor codeEditor;
371 GdbThread gdbThread { debugger = this };
374 delay = 0.0, userData = this;
378 bool monitor = false;
379 DebuggerEvent curEvent = event;
380 GdbDataStop stopItem = this.stopItem;
386 this.stopItem = null;
389 if(curEvent && curEvent != exit)
392 printf("No stop item\n");
400 Restart(currentCompiler, prjConfig, bitDepth);
409 GdbCommand(false, "-stack-select-frame %d", activeFrameLevel);
410 for(activeFrame = stackFrames.first; activeFrame; activeFrame = activeFrame.next)
411 if(activeFrame.level == activeFrameLevel)
417 // GdbCommand(false, "-break-info %d", bpItem.number);
427 activeThread = stopItem.threadid;
428 GdbCommand(false, "-thread-list-ids");
433 Breakpoint bp = null;
435 for(i : ide.workspace.breakpoints; i.bp && i.bp.number == stopItem.bkptno)
442 for(i : sysBPs; i.bp && i.bp.number == stopItem.bkptno)
448 if(bp && bp.type != user && stopItem && stopItem.frame)
450 // In case the user put a breakpoint where an internal breakpoint is, avoid the confusion...
451 for(i : ide.workspace.breakpoints)
453 if(i.bp && i.line == stopItem.frame.line && !fstrcmp(i.absoluteFilePath, stopItem.frame.absoluteFile))
460 if(!(!userBreakOnInternBreak &&
461 bp && (bp.type == internalMain || bp.type == internalWinMain ||
462 bp.type == internalModulesLoaded || bp.type == internalModuleLoad)))
464 hitThread = stopItem.threadid;
468 signalThread = stopItem.threadid;
480 activeThread = stopItem.threadid;
481 GdbCommand(false, "-thread-list-ids");
483 if(activeFrameLevel > 0)
484 GdbCommand(false, "-stack-select-frame %d", activeFrameLevel);
486 WatchesCodeEditorLinkInit();
496 ide.outputView.debugBox.Logf($"Signal received: %s - %s\n", stopItem.name, stopItem.meaning);
497 ide.outputView.debugBox.Logf(" %s:%d\n", (s = CopySystemPath(stopItem.frame.file)), stopItem.frame.line);
503 // Why was SelectFrame missing here?
504 SelectFrame(activeFrameLevel);
505 GoToStackFrameLine(activeFrameLevel, curEvent == signal || curEvent == stepEnd /*false*/);
506 ideMainFrame.Activate(); // TOFIX: ide.Activate() is not reliable (app inactive)
508 if(curEvent == signal)
509 ide.outputView.Show();
510 if(curEvent == signal || curEvent == breakEvent)
512 if(curEvent == breakEvent)
513 ide.threadsView.Show();
514 ide.callStackView.Show();
516 ide.ShowCodeEditor();
517 if(curEvent == breakEvent)
518 ide.callStackView.Activate();
526 ignoreBreakpoints = false;
537 #ifdef GDB_DEBUG_CONSOLE
538 char lastGdbOutput[GdbGetLineSize];
540 #if defined(__unix__)
541 ProgramThread progThread { };
544 void ChangeState(DebuggerState value)
546 bool same = value == state;
547 // if(same) PrintLn("Debugger::ChangeState -- changing to same state");
549 if(!same && ide) ide.AdjustDebugMenus();
554 // Stop(); // Don't need to call Stop here, because ~ProjectView() will call it explicitly.
556 stackFrames.Free(Frame::Free);
566 waitingForPID = false;
571 sentBreakInsert = false;
572 ignoreBreakpoints = false;
573 userBreakOnInternBreak = false;
576 activeFrameLevel = 0;
593 bpRunToCursor = null;
596 delete currentCompiler;
600 /*GdbThread gdbThread
606 ideProcessId = Process_GetCurrentProcessId();
608 sysBPs.Add(Breakpoint { type = internalMain, enabled = true, level = -1 });
609 #if defined(__WIN32__)
610 sysBPs.Add(Breakpoint { type = internalWinMain, enabled = true, level = -1 });
612 sysBPs.Add(Breakpoint { type = internalModulesLoaded, enabled = true, level = -1 });
613 sysBPs.Add(Breakpoint { type = internalModuleLoad, enabled = true, level = -1 });
625 property bool isActive { get { return state == running || state == stopped; } }
626 property bool isPrepared { get { return state == loaded || state == running || state == stopped; } }
630 GdbExecContinue(true);
638 GdbDebugBreak(false);
650 GdbDebugBreak(false);
661 void Restart(CompilerConfig compiler, ProjectConfig config, int bitDepth)
669 GdbDebugBreak(false);
676 if(!GdbInit(compiler, config, bitDepth))
684 bool GoToCodeLine(char * location)
687 codloc = CodeLocation::ParseCodeLocation(location);
690 CodeEditor editor = (CodeEditor)ide.OpenFile(codloc.absoluteFile, normal, true, null, no, normal);
693 EditBox editBox = editor.editBox;
694 editBox.GoToLineNum(codloc.line - 1);
695 editBox.GoToPosition(editBox.line, codloc.line - 1, 0);
702 bool GoToStackFrameLine(int stackLevel, bool askForLocation)
706 char filePath[MAX_LOCATION];
707 char sourceDir[MAX_LOCATION];
709 CodeEditor editor = null;
710 if(stackLevel == -1) // this (the two lines) is part of that fix that I would not put in for some time
712 for(frame = stackFrames.first; frame; frame = frame.next)
713 if(frame.level == stackLevel)
717 ide.callStackView.Show();
719 if(!frame.absoluteFile && frame.file)
720 frame.absoluteFile = ide.workspace.GetAbsolutePathFromRelative(frame.file);
721 if(!frame.absoluteFile && askForLocation && frame.file)
724 char title[MAX_LOCATION];
725 snprintf(title, sizeof(title), $"Provide source file location for %s", (s = CopySystemPath(frame.file)));
726 title[sizeof(title)-1] = 0;
728 if(SourceDirDialog(title, ide.workspace.projectDir, frame.file, sourceDir))
730 AddSourceDir(sourceDir);
731 frame.absoluteFile = ide.workspace.GetAbsolutePathFromRelative(frame.file);
734 if(frame.absoluteFile)
735 editor = (CodeEditor)ide.OpenFile(frame.absoluteFile, normal, true, null, no, normal);
737 if(editor && frame.line)
739 EditBox editBox = editor.editBox;
740 editBox.GoToLineNum(frame.line - 1);
741 editBox.GoToPosition(editBox.line, frame.line - 1, 0);
749 void SelectThread(int thread)
753 if(thread != activeThread)
755 activeFrameLevel = -1;
756 ide.callStackView.Clear();
757 GdbCommand(false, "-thread-select %d", thread);
759 // Why was SelectFrame missing here?
760 SelectFrame(activeFrameLevel);
761 GoToStackFrameLine(activeFrameLevel, true);
762 WatchesCodeEditorLinkRelease();
763 WatchesCodeEditorLinkInit();
767 ide.callStackView.Show();
771 void SelectFrame(int frame)
775 if(frame != activeFrameLevel || !codeEditor || !codeEditor.visible)
777 activeFrameLevel = frame; // there is no active frame number in the gdb reply
778 GdbCommand(false, "-stack-select-frame %d", activeFrameLevel);
779 for(activeFrame = stackFrames.first; activeFrame; activeFrame = activeFrame.next)
780 if(activeFrame.level == activeFrameLevel)
783 WatchesCodeEditorLinkRelease();
784 WatchesCodeEditorLinkInit();
791 void HandleExit(char * reason, char * code)
793 bool returnedExitCode = false;
794 char verboseExitCode[128];
796 ChangeState(loaded); // this state change seems to be superfluous, might be in case of gdb crash
801 snprintf(verboseExitCode, sizeof(verboseExitCode), $" with exit code %s", code);
802 verboseExitCode[sizeof(verboseExitCode)-1] = 0;
805 verboseExitCode[0] = '\0';
809 // ClearBreakDisplay();
813 for(wh : ide.workspace.watches)
815 if(wh.type) FreeType(wh.type);
818 ide.watchesView.UpdateWatch(wh);
822 #if defined(__unix__)
823 progThread.terminate = true;
826 fifoFile.CloseInput();
835 char program[MAX_LOCATION];
836 GetSystemPathBuffer(program, targetFile);
838 ide.outputView.debugBox.Logf($"The program %s has exited%s.\n", program, verboseExitCode);
839 else if(!strcmp(reason, "exited-normally"))
840 ide.outputView.debugBox.Logf($"The program %s has exited normally%s.\n", program, verboseExitCode);
841 else if(!strcmp(reason, "exited"))
842 ide.outputView.debugBox.Logf($"The program %s has exited%s.\n", program, verboseExitCode);
843 else if(!strcmp(reason, "exited-signalled"))
844 ide.outputView.debugBox.Logf($"The program %s has exited with a signal%s.\n", program, verboseExitCode);
846 ide.outputView.debugBox.Logf($"The program %s has exited (gdb provided an unknown reason)%s.\n", program, verboseExitCode);
851 void Start(CompilerConfig compiler, ProjectConfig config, int bitDepth)
853 ide.outputView.debugBox.Clear();
858 if(!GdbInit(compiler, config, bitDepth))
866 void StepInto(CompilerConfig compiler, ProjectConfig config, int bitDepth)
872 if(!GdbInit(compiler, config, bitDepth))
875 ide.outputView.ShowClearSelectTab(debug);
876 ide.outputView.debugBox.Logf($"Starting debug mode\n");
877 userBreakOnInternBreak = true;
886 void StepOver(CompilerConfig compiler, ProjectConfig config, int bitDepth, bool ignoreBkpts)
892 if(!GdbInit(compiler, config, bitDepth))
895 ide.outputView.ShowClearSelectTab(debug);
896 ide.outputView.debugBox.Logf($"Starting debug mode\n");
897 ignoreBreakpoints = ignoreBkpts;
898 userBreakOnInternBreak = true;
902 ignoreBreakpoints = ignoreBkpts;
903 if(ignoreBreakpoints)
904 GdbBreakpointsDelete(true);
910 void StepOut(bool ignoreBkpts)
914 ignoreBreakpoints = ignoreBkpts;
915 if(ignoreBreakpoints)
916 GdbBreakpointsDelete(true);
921 void RunToCursor(CompilerConfig compiler, ProjectConfig config, int bitDepth, char * absoluteFilePath, int lineNumber, bool ignoreBkpts)
923 char relativeFilePath[MAX_LOCATION];
924 DebuggerState oldState = state;
925 ignoreBreakpoints = ignoreBkpts;
926 if(!ide.projectView.GetRelativePath(absoluteFilePath, relativeFilePath))
927 strcpy(relativeFilePath, absoluteFilePath);
932 Start(compiler, config, bitDepth);
939 ide.outputView.ShowClearSelectTab(debug);
940 ide.outputView.debugBox.Logf($"Starting debug mode\n");
942 RunToCursorPrepare(absoluteFilePath, relativeFilePath, lineNumber);
943 sentBreakInsert = true;
944 GdbCommand(false, "-break-insert %s:%d", relativeFilePath, lineNumber);
945 bpRunToCursor.bp = bpItem;
947 bpRunToCursor.inserted = (bpRunToCursor.bp.number != 0);
948 ValidateBreakpoint(bpRunToCursor);
955 if(ignoreBreakpoints)
956 GdbBreakpointsDelete(false);
960 if(ignoreBreakpoints)
961 GdbBreakpointsDelete(false);
962 GdbExecContinue(true);
968 void GetCallStackCursorLine(bool * error, int * lineCursor, int * lineTopFrame)
970 if(activeFrameLevel == -1)
978 *error = signalOn && activeThread == signalThread;
979 *lineCursor = activeFrameLevel - ((frameCount > 192 && activeFrameLevel > 191) ? frameCount - 192 - 1 : 0) + 1;
980 *lineTopFrame = activeFrameLevel ? 1 : 0;
984 int GetMarginIconsLineNumbers(char * fileName, int lines[], bool enabled[], int max, bool * error, int * lineCursor, int * lineTopFrame)
986 char winFilePath[MAX_LOCATION];
987 char * absoluteFilePath = GetSlashPathBuffer(winFilePath, fileName);
989 Iterator<Breakpoint> it { ide.workspace.breakpoints };
990 while(it.Next() && count < max)
992 Breakpoint bp = it.data;
995 if(bp.absoluteFilePath && bp.absoluteFilePath[0] && !fstrcmp(bp.absoluteFilePath, absoluteFilePath))
997 lines[count] = bp.line;
998 enabled[count] = bp.enabled;
1003 if(activeFrameLevel == -1)
1011 *error = signalOn && activeThread == signalThread;
1012 if(activeFrame && activeFrame.absoluteFile && !fstrcmp(absoluteFilePath, activeFrame.absoluteFile))
1013 *lineCursor = activeFrame.line;
1016 if(activeFrame && stopItem && stopItem.frame && activeFrame.level == stopItem.frame.level)
1018 else if(stopItem && stopItem.frame && stopItem.frame.absoluteFile && !fstrcmp(absoluteFilePath, stopItem.frame.absoluteFile))
1019 *lineTopFrame = stopItem.frame.line;
1023 if(*lineTopFrame == *lineCursor && *lineTopFrame)
1029 void ChangeWatch(DataRow row, char * expression)
1031 Watch wh = (Watch)row.tag;
1034 delete wh.expression;
1036 wh.expression = CopyString(expression);
1039 Iterator<Watch> it { ide.workspace.watches };
1041 ide.workspace.watches.Delete(it.pointer);
1047 row.tag = (int64)wh;
1048 ide.workspace.watches.Add(wh);
1050 wh.expression = CopyString(expression);
1052 ide.workspace.Save();
1053 //if(expression && state == stopped)
1058 void MoveIcons(char * fileName, int lineNumber, int move, bool start)
1060 char winFilePath[MAX_LOCATION];
1061 char * absoluteFilePath = GetSlashPathBuffer(winFilePath, fileName);
1064 for(bpLink = ide.workspace.breakpoints.first; bpLink; bpLink = next)
1066 Breakpoint bp = (Breakpoint)bpLink.data;
1069 if(bp.type == user && bp.absoluteFilePath && !fstrcmp(bp.absoluteFilePath, absoluteFilePath))
1071 if(bp.line > lineNumber || (bp.line == lineNumber && start))
1073 if(move < 0 && (bp.line < lineNumber - move))
1074 ide.workspace.RemoveBreakpoint(bp);
1078 ide.breakpointsView.UpdateBreakpoint(bp.row);
1079 ide.workspace.Save();
1085 // moving code cursors is futile, on next step, stop, hit, cursors will be offset anyways
1088 bool SourceDirDialog(char * title, char * startDir, char * test, char * sourceDir)
1092 String srcDir = null;
1094 debuggerFileDialog.text = title;
1095 debuggerFileDialog.currentDirectory = startDir;
1096 debuggerFileDialog.master = ide;
1098 while(debuggerFileDialog.Modal())
1100 strcpy(sourceDir, debuggerFileDialog.filePath);
1101 if(!fstrcmp(ide.workspace.projectDir, sourceDir) &&
1102 MessageBox { type = yesNo, master = ide,
1103 contents = $"This is the project directory.\nWould you like to try again?",
1104 text = $"Invalid Source Directory" }.Modal() == no)
1108 for(dir : ide.workspace.sourceDirs)
1110 if(!fstrcmp(dir, sourceDir))
1118 MessageBox { type = yesNo, master = ide,
1119 contents = $"This source directory is already specified.\nWould you like to try again?",
1120 text = $"Invalid Source Directory" }.Modal() == no)
1126 char file[MAX_LOCATION];
1127 strcpy(file, sourceDir);
1128 PathCat(file, test);
1129 result = FileExists(file);
1131 MessageBox { type = yesNo, master = ide,
1132 contents = $"Unable to locate source file.\nWould you like to try again?",
1133 text = $"Invalid Source Directory" }.Modal() == no)
1147 void AddSourceDir(char * sourceDir)
1149 ide.workspace.sourceDirs.Add(CopyString(sourceDir));
1150 ide.workspace.Save();
1154 DebuggerState oldState = state;
1159 GdbDebugBreak(true);
1162 GdbCommand(false, "-environment-directory \"%s\"", sourceDir);
1165 if(oldState == running)
1166 GdbExecContinue(false);
1170 void ToggleBreakpoint(char * fileName, int lineNumber, Project prj)
1172 char winFilePath[MAX_LOCATION];
1173 char * absoluteFilePath = GetSlashPathBuffer(winFilePath, fileName);
1174 char absolutePath[MAX_LOCATION];
1175 char relativePath[MAX_LOCATION];
1176 char sourceDir[MAX_LOCATION];
1177 Breakpoint bp = null;
1179 strcpy(absolutePath, absoluteFilePath);
1180 for(i : ide.workspace.breakpoints; i.type == user && i.absoluteFilePath && !fstrcmp(i.absoluteFilePath, absolutePath) && i.line == lineNumber)
1189 ide.workspace.RemoveBreakpoint(bp);
1197 // FIXED: This is how it should have been... Source locations are only for files not in project
1198 // if(IsPathInsideOf(absolutePath, ide.workspace.projectDir))
1199 // MakePathRelative(absolutePath, ide.workspace.projectDir, relativePath);
1200 bool result = false;
1202 result = prj.GetRelativePath(absolutePath, relativePath);
1204 ide.projectView.GetRelativePath(absolutePath, relativePath);
1205 //if(ide.projectView.GetRelativePath(absolutePath, relativePath));
1209 char title[MAX_LOCATION];
1210 char directory[MAX_LOCATION];
1211 StripLastDirectory(absolutePath, directory);
1212 snprintf(title, sizeof(title), $"Provide source files location directory for %s", absolutePath);
1213 title[sizeof(title)-1] = 0;
1216 String srcDir = null;
1217 for(dir : ide.workspace.sourceDirs)
1219 if(IsPathInsideOf(absolutePath, dir))
1221 MakePathRelative(absoluteFilePath, dir, relativePath);
1229 if(SourceDirDialog(title, directory, null, sourceDir))
1231 if(IsPathInsideOf(absolutePath, sourceDir))
1233 AddSourceDir(sourceDir);
1234 MakePathRelative(absoluteFilePath, sourceDir, relativePath);
1237 else if(MessageBox { type = yesNo, master = ide,
1238 contents = $"You must provide a valid source directory in order to place a breakpoint in this file.\nWould you like to try again?",
1239 text = $"Invalid Source Directory" }.Modal() == no)
1242 else if(MessageBox { type = yesNo, master = ide,
1243 contents = $"You must provide a source directory in order to place a breakpoint in this file.\nWould you like to try again?",
1244 text = $"No Source Directory Provided" }.Modal() == no)
1248 ide.workspace.bpCount++;
1249 bp = { line = lineNumber, type = user, enabled = true, level = -1 };
1250 ide.workspace.breakpoints.Add(bp);
1251 bp.absoluteFilePath = CopyString(absolutePath);
1252 bp.relativeFilePath = CopyString(relativePath);
1253 ide.breakpointsView.AddBreakpoint(bp);
1258 DebuggerState oldState = state;
1263 GdbDebugBreak(true);
1268 sentBreakInsert = true;
1269 GdbCommand(false, "-break-insert %s:%d", bp.relativeFilePath, bp.line);
1272 bp.inserted = (bp.bp && bp.bp.number != 0);
1273 ValidateBreakpoint(bp);
1277 if(oldState == running)
1278 GdbExecContinue(false);
1281 ide.workspace.Save();
1284 void UpdateRemovedBreakpoint(Breakpoint bp)
1286 if(targeted && bp.inserted)
1288 DebuggerState oldState = state;
1293 GdbDebugBreak(true);
1297 GdbCommand(false, "-break-delete %d", bp.bp.number);
1300 if(oldState == running)
1301 GdbExecContinue(false);
1307 void ParseFrame(Frame frame, char * string)
1310 Array<char *> frameTokens { minAllocSize = 50 };
1311 Array<char *> argsTokens { minAllocSize = 50 };
1312 Array<char *> argumentTokens { minAllocSize = 50 };
1313 DebugListItem item { };
1316 TokenizeList(string, ',', frameTokens);
1317 for(i = 0; i < frameTokens.count; i++)
1319 if(TokenizeListItem(frameTokens[i], item))
1321 StripQuotes(item.value, item.value);
1322 if(!strcmp(item.name, "level"))
1323 frame.level = atoi(item.value);
1324 else if(!strcmp(item.name, "addr"))
1325 frame.addr = CopyString(item.value);
1326 else if(!strcmp(item.name, "func"))
1327 frame.func = CopyString(item.value);
1328 else if(!strcmp(item.name, "args"))
1330 if(!strcmp(item.value, "[]"))
1331 frame.argsCount = 0;
1334 item.value = StripBrackets(item.value);
1335 TokenizeList(item.value, ',', argsTokens);
1336 for(j = 0; j < argsTokens.count; j++)
1338 argsTokens[j] = StripCurlies(argsTokens[j]);
1339 TokenizeList(argsTokens[j], ',', argumentTokens);
1340 for(k = 0; k < argumentTokens.count; k++)
1343 frame.args.Add(arg);
1344 if(TokenizeListItem(argumentTokens[k], item))
1346 if(!strcmp(item.name, "name"))
1348 StripQuotes(item.value, item.value);
1349 arg.name = CopyString(item.value);
1351 else if(!strcmp(item.name, "value"))
1353 StripQuotes(item.value, item.value);
1354 arg.value = CopyString(item.value);
1357 DebuggerProtocolUnknown("Unknown frame args item name", item.name);
1360 DebuggerProtocolUnknown("Bad frame args item", "");
1362 argumentTokens.RemoveAll();
1364 frame.argsCount = argsTokens.count;
1365 argsTokens.RemoveAll();
1368 else if(!strcmp(item.name, "from"))
1369 frame.from = item.value;
1370 else if(!strcmp(item.name, "file"))
1372 frame.file = item.value;
1373 frame.absoluteFile = ide.workspace.GetAbsolutePathFromRelative(frame.file);
1375 else if(!strcmp(item.name, "line"))
1376 frame.line = atoi(item.value);
1377 else if(!strcmp(item.name, "fullname"))
1379 // GDB 6.3 on OS X is giving "fullname" and "dir", all in absolute, but file name only in 'file'
1380 String path = ide.workspace.GetPathWorkspaceRelativeOrAbsolute(item.value);
1381 if(strcmp(frame.file, path))
1384 delete frame.absoluteFile;
1385 frame.absoluteFile = ide.workspace.GetAbsolutePathFromRelative(frame.file);
1390 DebuggerProtocolUnknown("Unknown frame member name", item.name);
1393 DebuggerProtocolUnknown("Bad frame", "");
1398 delete argumentTokens;
1402 void ShowDebuggerViews()
1404 ide.outputView.Show();
1405 ide.outputView.SelectTab(debug);
1406 ide.threadsView.Show();
1407 ide.callStackView.Show();
1408 ide.watchesView.Show();
1412 void HideDebuggerViews()
1414 ide.RepositionWindows(true);
1417 void ::GdbCommand(bool focus, char * format, ...)
1421 // TODO: Improve this limit
1422 static char string[MAX_F_STRING*3];
1424 va_start(args, format);
1425 vsnprintf(string, sizeof(string), format, args);
1426 string[sizeof(string)-1] = 0;
1430 ide.debugger.serialSemaphore.TryWait();
1433 #ifdef GDB_DEBUG_CONSOLE
1434 Log(string); Log("\n");
1436 #ifdef GDB_DEBUG_OUTPUT
1437 ide.outputView.gdbBox.Logf("cmd: %s\n", string);
1439 #ifdef GDB_DEBUG_GUI
1441 ide.gdbDialog.AddCommand(string);
1443 strcat(string,"\n");
1444 gdbHandle.Puts(string);
1447 Process_ShowWindows(targetProcessId);
1450 ide.debugger.serialSemaphore.Wait();
1455 bool ValidateBreakpoint(Breakpoint bp)
1457 if(modules && bp.bp)
1459 if(bp.bp.line != bp.line)
1464 ide.outputView.debugBox.Logf("WOULD HAVE -- Invalid breakpoint disabled: %s:%d\n", bp.relativeFilePath, bp.line);
1468 //GdbCommand(false, "-break-delete %d", bp.bp.number);
1469 //bp.inserted = false;
1471 //bp.enabled = false;
1476 ide.outputView.debugBox.Logf("Debugger Error: ValidateBreakpoint error\n");
1477 bp.line = bp.bp.line;
1484 static void GdbInsertInternalBreakpoint()
1488 //if(!breakpointsInserted)
1490 DirExpression objDir = ide.project.GetObjDir(currentCompiler, prjConfig, bitDepth);
1495 if(bp.type == internalMain)
1497 sentBreakInsert = true;
1498 GdbCommand(false, "-break-insert main");
1501 bp.inserted = (bp.bp && bp.bp.number != 0);
1503 #if defined(__WIN32__)
1504 else if(bp.type == internalWinMain)
1506 sentBreakInsert = true;
1507 GdbCommand(false, "-break-insert WinMain");
1510 bp.inserted = (bp.bp && bp.bp.number != 0);
1513 else if(bp.type == internalModulesLoaded)
1515 char path[MAX_LOCATION];
1516 char name[MAX_LOCATION];
1517 char fixedModuleName[MAX_FILENAME];
1520 bool moduleLoadBlock = false;
1522 ReplaceSpaces(fixedModuleName, ide.project.moduleName);
1523 snprintf(name, sizeof(name),"%s.main.ec", fixedModuleName);
1524 name[sizeof(name)-1] = 0;
1525 strcpy(path, ide.workspace.projectDir);
1526 PathCatSlash(path, objDir.dir);
1527 PathCatSlash(path, name);
1528 f = FileOpen(path, read);
1531 for(lineNumber = 1; !f.Eof(); lineNumber++)
1533 if(f.GetLine(line, sizeof(line) - 1))
1535 bool moduleLoadLine;
1536 TrimLSpaces(line, line);
1537 moduleLoadLine = !strncmp(line, "eModule_Load", strlen("eModule_Load"));
1538 if(!moduleLoadBlock && moduleLoadLine)
1539 moduleLoadBlock = true;
1540 else if(moduleLoadBlock && !moduleLoadLine && strlen(line) > 0)
1546 char relative[MAX_LOCATION];
1547 bp.absoluteFilePath = CopyString(path);
1548 MakePathRelative(path, ide.workspace.projectDir, relative);
1549 delete bp.relativeFilePath;
1550 bp.relativeFilePath = CopyString(relative);
1551 bp.line = lineNumber;
1552 sentBreakInsert = true;
1553 GdbCommand(false, "-break-insert %s:%d", bp.relativeFilePath, lineNumber);
1556 bp.inserted = (bp.bp && bp.bp.number != 0);
1561 else if(bp.type == internalModuleLoad && modules)
1563 Project ecerePrj = null;
1564 for(p : ide.workspace.projects)
1566 if(!strcmp(p.topNode.name, "ecere.epj"))
1574 ProjectNode node = ecerePrj.topNode.Find("instance.c", false);
1577 char path[MAX_LOCATION];
1578 char relative[MAX_LOCATION];
1579 node.GetFullFilePath(path);
1580 bp.absoluteFilePath = CopyString(path);
1581 MakePathRelative(path, ecerePrj.topNode.path, relative);
1582 delete bp.relativeFilePath;
1583 bp.relativeFilePath = CopyString(relative);
1584 sentBreakInsert = true;
1585 GdbCommand(false, "-break-insert %s:InternalModuleLoadBreakpoint", bp.relativeFilePath);
1588 bp.inserted = (bp.bp && bp.bp.number != 0);
1599 void GdbBreakpointsInsert()
1603 //if(!breakpointsInserted)
1605 //if(!ignoreBreakpoints)
1606 //breakpointsInserted = true;
1607 for(bp : ide.workspace.breakpoints)
1609 if(!bp.inserted && bp.type == user)
1611 if(!ignoreBreakpoints && bp.enabled)
1613 sentBreakInsert = true;
1614 breakpointError = false;
1615 GdbCommand(false, "-break-insert %s:%d", bp.relativeFilePath, bp.line);
1616 // Improve, GdbCommand should return a success value?
1619 char fileName[MAX_FILENAME];
1620 breakpointError = false;
1621 GetLastDirectory(bp.relativeFilePath, fileName);
1622 sentBreakInsert = true;
1623 GdbCommand(false, "-break-insert %s:%d", fileName, bp.line);
1627 bp.inserted = (bp.bp && bp.bp.number != 0);
1630 ValidateBreakpoint(bp);
1636 printf("problem\n");
1638 bp.bp = GdbDataBreakpoint { };
1642 if(bpRunToCursor && !bpRunToCursor.inserted)
1644 sentBreakInsert = true;
1645 GdbCommand(false, "-break-insert %s:%d", bpRunToCursor.relativeFilePath, bpRunToCursor.line);
1646 bpRunToCursor.bp = bpItem;
1648 bpRunToCursor.inserted = (bpRunToCursor.bp && bpRunToCursor.bp.number != 0);
1649 ValidateBreakpoint(bpRunToCursor);
1655 void GdbBreakpointsDelete(bool deleteRunToCursor)
1657 //breakpointsInserted = false;
1660 for(bp : ide.workspace.breakpoints)
1663 GdbCommand(false, "-break-delete %d", bp.bp.number);
1664 bp.inserted = false;
1666 //check here (reply form -break-delete, returns bpitem?)
1669 if(deleteRunToCursor && bpRunToCursor)
1671 GdbCommand(false, "-break-delete %d", bpRunToCursor.bp.number);
1672 bpRunToCursor.inserted = false;
1673 bpRunToCursor.bp = bpItem;
1674 //check here (reply form -break-delete, returns bpitem?)
1683 stackFrames.Free(Frame::Free);
1684 GdbCommand(false, "-stack-info-depth");
1686 GdbCommand(false, "-stack-info-depth 192");
1687 if(frameCount && frameCount <= 192)
1688 GdbCommand(false, "-stack-list-frames 0 %d", Min(frameCount-1, 191));
1691 GdbCommand(false, "-stack-list-frames 0 %d", Min(frameCount-1, 95));
1692 GdbCommand(false, "-stack-list-frames %d %d", Max(frameCount - 96, 96), frameCount - 1);
1694 GdbCommand(false, "");
1701 char escaped[MAX_LOCATION];
1702 strescpy(escaped, targetFile);
1703 GdbCommand(false, "file \"%s\"", escaped); //GDB/MI Missing Implementation -symbol-file, -target-attach
1708 for(prj : ide.workspace.projects)
1710 if(prj == ide.workspace.projects.firstIterator.data)
1713 //PrintLn("THIS: ", (String)prj.topNode.path);
1714 GdbCommand(false, "-environment-directory \"%s\"", prj.topNode.path);
1715 //GdbCommand(false, ""); // why this empty GDB command
1718 for(dir : ide.workspace.sourceDirs)
1720 GdbCommand(false, "-environment-directory \"%s\"", dir);
1721 //GdbCommand(false, ""); // why this empty GDB command
1723 GdbInsertInternalBreakpoint();
1729 void GdbTargetRelease()
1733 GdbBreakpointsDelete(true);
1734 GdbCommand(false, "file"); //GDB/MI Missing Implementation -target-detach
1740 void GdbDebugBreak(bool internal)
1745 breakType = DebuggerAction::internal;
1747 if(ide) ide.Update(null);
1749 if(Process_Break(targetProcessId)) //GdbCommand(false, "-exec-interrupt");
1750 serialSemaphore.Wait();
1753 ChangeState(loaded);
1754 targetProcessId = 0;
1759 ide.outputView.debugBox.Logf("Debugger Error: GdbDebugBreak with not target id should never happen\n");
1766 ShowDebuggerViews();
1767 GdbCommand(true, "-exec-run");
1770 void GdbExecContinue(bool focus)
1773 GdbCommand(focus, "-exec-continue");
1779 GdbCommand(true, "-exec-next");
1785 GdbCommand(true, "-exec-step");
1788 void GdbExecFinish()
1791 GdbCommand(true, "-exec-finish");
1794 void GdbExecCommon()
1796 ClearBreakDisplay();
1797 GdbBreakpointsInsert();
1800 #ifdef GDB_DEBUG_GUI
1801 void SendGDBCommand(char * command)
1803 DebuggerState oldState = state;
1808 GdbDebugBreak(true);
1811 GdbCommand(false, command);
1814 if(oldState == running)
1815 GdbExecContinue(false);
1819 void ClearBreakDisplay()
1822 activeFrameLevel = -1;
1833 stackFrames.Free(Frame::Free);
1834 WatchesCodeEditorLinkRelease();
1835 ide.callStackView.Clear();
1836 ide.threadsView.Clear();
1843 GdbCommand(false, "-interpreter-exec console \"kill\""); // should use -exec-abort -- GDB/MI implementation incomplete
1847 bool GdbInit(CompilerConfig compiler, ProjectConfig config, int bitDepth)
1850 char oldDirectory[MAX_LOCATION];
1851 char tempPath[MAX_LOCATION];
1852 char command[MAX_LOCATION];
1853 Project project = ide.project;
1854 DirExpression targetDirExp = project.GetTargetDir(compiler, config, bitDepth);
1855 PathBackup pathBackup { };
1857 if(currentCompiler != compiler)
1859 delete currentCompiler;
1860 currentCompiler = compiler;
1861 incref currentCompiler;
1864 this.bitDepth = bitDepth;
1866 ChangeState(loaded);
1868 sentBreakInsert = false;
1869 breakpointError = false;
1873 //breakpointsInserted = false;
1875 ide.outputView.ShowClearSelectTab(debug);
1876 ide.outputView.debugBox.Logf($"Starting debug mode\n");
1878 #ifdef GDB_DEBUG_CONSOLE
1879 Log("Starting GDB"); Log("\n");
1881 #ifdef GDB_DEBUG_OUTPUT
1882 ide.outputView.gdbBox.Logf("run: Starting GDB\n");
1885 strcpy(tempPath, ide.workspace.projectDir);
1886 PathCatSlash(tempPath, targetDirExp.dir);
1888 targetDir = CopyString(tempPath);
1889 project.CatTargetFileName(tempPath, compiler, config);
1891 targetFile = CopyString(tempPath);
1893 GetWorkingDir(oldDirectory, MAX_LOCATION);
1894 if(ide.workspace.debugDir && ide.workspace.debugDir[0])
1896 char temp[MAX_LOCATION];
1897 strcpy(temp, ide.workspace.projectDir);
1898 PathCatSlash(temp, ide.workspace.debugDir);
1899 ChangeWorkingDir(temp);
1902 ChangeWorkingDir(ide.workspace.projectDir);
1904 ide.SetPath(true, compiler, config, bitDepth);
1906 // TODO: This pollutes the environment, but at least it works
1907 // It shouldn't really affect the IDE as the PATH gets restored and other variables set for testing will unlikely cause problems
1908 // What is the proper solution for this? DualPipeOpenEnv?
1909 // gdb set environment commands don't seem to take effect
1910 for(e : ide.workspace.environmentVars)
1912 SetEnvironment(e.name, e.string);
1916 (compiler.targetPlatform == win32 && bitDepth == 64) ? "x86_64-w64-mingw32-gdb" :
1917 (compiler.targetPlatform == win32 && bitDepth == 32) ? "i686-w64-mingw32-gdb" :
1919 strcat(command, " -n -silent --interpreter=mi2"); //-async //\"%s\"
1921 gdbHandle = DualPipeOpen(PipeOpenMode { output = 1, error = 2, input = 1 }, command);
1924 ide.outputView.debugBox.Logf($"Debugger Fatal Error: Couldn't start GDB\n");
1932 gdbProcessId = gdbHandle.GetProcessID();
1935 ide.outputView.debugBox.Logf($"Debugger Fatal Error: Couldn't get GDB process ID\n");
1941 serialSemaphore.Wait();
1946 //ChangeState(terminated);
1952 #if defined(__unix__)
1954 CreateTemporaryDir(progFifoDir, "ecereide");
1955 strcpy(progFifoPath, progFifoDir);
1956 PathCat(progFifoPath, "ideprogfifo");
1957 if(!mkfifo(progFifoPath, 0600))
1959 //fileCreated = true;
1964 ide.outputView.debugBox.Logf(createFIFOMsg, progFifoPath);
1969 progThread.terminate = false;
1970 progThread.Create();
1973 #if defined(__WIN32__)
1974 GdbCommand(false, "-gdb-set new-console on");
1977 GdbCommand(false, "-gdb-set verbose off");
1978 //GdbCommand(false, "-gdb-set exec-done-display on");
1979 GdbCommand(false, "-gdb-set step-mode off");
1980 GdbCommand(false, "-gdb-set unwindonsignal on");
1981 //GdbCommand(false, "-gdb-set shell on");
1982 GdbCommand(false, "set print elements 992");
1983 GdbCommand(false, "-gdb-set backtrace limit 100000");
1985 #if defined(__unix__)
1986 GdbCommand(false, "-inferior-tty-set %s", progFifoPath);
1989 GdbCommand(false, "-gdb-set args %s", ide.workspace.commandLineArgs ? ide.workspace.commandLineArgs : "");
1991 for(e : ide.workspace.environmentVars)
1993 GdbCommand(false, "set environment %s=%s", e.name, e.string);
2000 ChangeWorkingDir(oldDirectory);
2006 delete targetDirExp;
2012 if(gdbHandle && gdbProcessId)
2014 GdbCommand(false, "-gdb-exit");
2029 ChangeState(terminated); // this state change seems to be superfluous, is it safety for something?
2033 for(bp : ide.workspace.breakpoints)
2034 bp.inserted = false;
2036 bp.inserted = false;
2038 bpRunToCursor.inserted = false;
2040 ide.outputView.debugBox.Logf($"Debugging stopped\n");
2041 ClearBreakDisplay();
2044 #if defined(__unix__)
2045 if(FileExists(progFifoPath)) //fileCreated)
2047 progThread.terminate = true;
2050 fifoFile.CloseInput();
2056 DeleteFile(progFifoPath);
2057 progFifoPath[0] = '\0';
2063 void WatchesCodeEditorLinkInit()
2066 char tempPath[MAX_LOCATION];
2067 char path[MAX_LOCATION];
2069 //void MakeFilePathProjectRelative(char * path, char * relativePath)
2070 if(!ide.projectView.GetRelativePath(activeFrame.file, tempPath))
2071 strcpy(tempPath, activeFrame.file);
2073 strcpy(path, ide.workspace.projectDir);
2074 PathCat(path, tempPath);
2075 codeEditor = (CodeEditor)ide.OpenFile(path, Normal, false, null, no);
2078 for(srcDir : ide.workspace.sourceDirs)
2080 strcpy(path, srcDir);
2081 PathCat(path, tempPath);
2082 codeEditor = (CodeEditor)ide.OpenFile(path, Normal, false, null, no);
2083 if(codeEditor) break;
2088 if(activeFrame && !activeFrame.absoluteFile && activeFrame.file)
2089 activeFrame.absoluteFile = ide.workspace.GetAbsolutePathFromRelative(activeFrame.file);
2090 if(!activeFrame || !activeFrame.absoluteFile)
2093 codeEditor = (CodeEditor)ide.OpenFile(activeFrame.absoluteFile, normal, false, null, no, normal);
2096 codeEditor.inUseDebug = true;
2099 //watchesInit = true;
2102 void WatchesCodeEditorLinkRelease()
2108 codeEditor.inUseDebug = false;
2109 if(!codeEditor.visible)
2110 codeEditor.Destroy(0);
2116 bool ResolveWatch(Watch wh)
2118 bool result = false;
2131 char watchmsg[MAX_F_STRING];
2132 if(state == stopped && !codeEditor)
2133 wh.value = CopyString($"No source file found for selected frame");
2134 //if(codeEditor && state == stopped || state != stopped)
2137 Module backupPrivateModule;
2138 Context backupContext;
2139 Class backupThisClass;
2143 backupPrivateModule = GetPrivateModule();
2144 backupContext = GetCurrentContext();
2145 backupThisClass = GetThisClass();
2148 SetPrivateModule(codeEditor.privateModule);
2149 SetCurrentContext(codeEditor.globalContext);
2150 SetTopContext(codeEditor.globalContext);
2151 SetGlobalContext(codeEditor.globalContext);
2152 SetGlobalData(&codeEditor.globalData);
2155 exp = ParseExpressionString(wh.expression);
2157 if(exp && !parseError)
2159 if(GetPrivateModule())
2162 DebugFindCtxTree(codeEditor.ast, activeFrame.line, 0);
2163 ProcessExpressionType(exp);
2165 wh.type = exp.expType;
2168 DebugComputeExpression(exp);
2170 /*if(exp.hasAddress)
2172 char temp[MAX_F_STRING];
2173 sprintf(temp, "0x%x", exp.address);
2174 wh.address = CopyString(temp);
2175 // wh.address = CopyStringf("0x%x", exp.address);
2180 Type dataType = exp.expType;
2183 char temp[MAX_F_STRING];
2184 switch(dataType.kind)
2187 sprintf(temp, "%i", exp.val.c);
2190 sprintf(temp, "%i", exp.val.s);
2195 sprintf(temp, "%i", exp.val.i);
2198 sprintf(temp, "%i", exp.val.i64);
2201 sprintf(temp, "%i", exp.val.p);
2206 long v = (long)exp.val.f;
2207 sprintf(temp, "%i", v);
2212 long v = (long)exp.val.d;
2213 sprintf(temp, "%i", v);
2218 wh.intVal = CopyString(temp);
2219 switch(dataType.kind)
2222 sprintf(temp, "0x%x", exp.val.c);
2225 sprintf(temp, "0x%x", exp.val.s);
2229 sprintf(temp, "0x%x", exp.val.i);
2232 sprintf(temp, "0x%x", exp.val.i64);
2235 sprintf(temp, "0x%x", exp.val.i64);
2238 sprintf(temp, "0x%x", exp.val.p);
2243 long v = (long)exp.val.f;
2244 sprintf(temp, "0x%x", v);
2249 long v = (long)exp.val.d;
2250 sprintf(temp, "0x%x", v);
2255 wh.hexVal = CopyString(temp);
2256 switch(dataType.kind)
2259 sprintf(temp, "0o%o", exp.val.c);
2262 sprintf(temp, "0o%o", exp.val.s);
2266 sprintf(temp, "0o%o", exp.val.i);
2269 sprintf(temp, "0o%o", exp.val.i64);
2272 sprintf(temp, "0o%o", exp.val.i64);
2275 sprintf(temp, "0o%o", exp.val.p);
2280 long v = (long)exp.val.f;
2281 sprintf(temp, "0o%o", v);
2286 long v = (long)exp.val.d;
2287 sprintf(temp, "0o%o", v);
2292 wh.octVal = CopyString(temp);
2295 // WHATS THIS HERE ?
2296 if(exp.type == constantExp && exp.constant)
2297 wh.constant = CopyString(exp.constant);
2303 case symbolErrorExp:
2304 snprintf(watchmsg, sizeof(watchmsg), $"Symbol \"%s\" not found", exp.identifier.string);
2306 case structMemberSymbolErrorExp:
2307 // todo get info as in next case (ExpClassMemberSymbolError)
2308 snprintf(watchmsg, sizeof(watchmsg), $"Error: Struct member not found for \"%s\"", wh.expression);
2310 case classMemberSymbolErrorExp:
2313 Expression memberExp = exp.member.exp;
2314 Identifier memberID = exp.member.member;
2315 Type type = memberExp.expType;
2318 _class = (memberID && memberID.classSym) ? memberID.classSym.registered : ((type.kind == classType && type._class) ? type._class.registered : null);
2321 char string[256] = "";
2323 PrintTypeNoConst(type, string, false, true);
2324 classSym = FindClass(string);
2325 _class = classSym ? classSym.registered : null;
2328 snprintf(watchmsg, sizeof(watchmsg), $"Member \"%s\" not found in class \"%s\"", memberID ? memberID.string : "", _class.name);
2330 snprintf(watchmsg, sizeof(watchmsg), "Member \"%s\" not found in unregistered class? (Should never get this message)", memberID ? memberID.string : "");
2333 snprintf(watchmsg, sizeof(watchmsg), "Member \"%s\" not found in no type? (Should never get this message)", memberID ? memberID.string : "");
2336 case memoryErrorExp:
2337 // Need to ensure when set to memoryErrorExp, constant is set
2338 snprintf(watchmsg, sizeof(watchmsg), $"Memory can't be read at %s", /*(exp.type == constantExp) ? */exp.constant /*: null*/);
2340 case dereferenceErrorExp:
2341 snprintf(watchmsg, sizeof(watchmsg), $"Dereference failure for \"%s\"", wh.expression);
2343 case unknownErrorExp:
2344 snprintf(watchmsg, sizeof(watchmsg), $"Unknown error for \"%s\"", wh.expression);
2346 case noDebuggerErrorExp:
2347 snprintf(watchmsg, sizeof(watchmsg), $"Debugger required for symbol evaluation in \"%s\"", wh.expression);
2349 case debugStateErrorExp:
2350 snprintf(watchmsg, sizeof(watchmsg), $"Incorrect debugger state for symbol evaluation in \"%s\"", wh.expression);
2353 snprintf(watchmsg, sizeof(watchmsg), $"Null type for \"%s\"", wh.expression);
2357 // Temporary Code for displaying Strings
2358 if((exp.expType && ((exp.expType.kind == pointerType ||
2359 exp.expType.kind == arrayType) && exp.expType.type.kind == charType)) ||
2360 (wh.type && wh.type.kind == classType && wh.type._class &&
2361 wh.type._class.registered && wh.type._class.registered.type == normalClass &&
2362 !strcmp(wh.type._class.registered.name, "String")))
2365 if(exp.expType.kind != arrayType || exp.hasAddress)
2371 //char temp[MAX_F_STRING * 32];
2373 ExpressionType evalError = dummyExp;
2374 /*if(exp.expType.kind == arrayType)
2375 sprintf(temp, "(char*)0x%x", exp.address);
2377 sprintf(temp, "(char*)%s", exp.constant);*/
2379 //evaluation = Debugger::EvaluateExpression(temp, &evalError);
2380 // address = strtoul(exp.constant, null, 0);
2381 address = _strtoui64(exp.constant, null, 0);
2382 //printf("%x\n", address);
2383 // snprintf(value, sizeof(value), "0x%08x ", address);
2385 if(address > 0xFFFFFFFFLL)
2386 snprintf(value, sizeof(value), (GetRuntimePlatform() == win32) ? "0x%016I64x " : "0x%016llx ", address);
2388 snprintf(value, sizeof(value), (GetRuntimePlatform() == win32) ? "0x%08I64x " : "0x%08llx ", address);
2389 value[sizeof(value)-1] = 0;
2392 strcat(value, $"Null string");
2396 len = strlen(value);
2398 while(!string && size > 2)
2400 string = GdbReadMemory(address, size);
2403 if(string && string[0])
2406 if(UTF8Validate(string))
2411 for(c = 0; (ch = string[c]) && c<4096; c++)
2414 value[len++] = '\0';
2419 ISO8859_1toUTF8(string, value + len, 4096 - len - 30);
2420 strcat(value, ") (ISO8859-1)");
2427 strcat(value, $"Empty string");
2431 strcat(value, $"Couldn't read memory");
2433 wh.value = CopyString(value);
2436 else if(wh.type && wh.type.kind == classType && wh.type._class &&
2437 wh.type._class.registered && wh.type._class.registered.type == enumClass)
2439 uint64 value = strtoul(exp.constant, null, 0);
2440 Class enumClass = eSystem_FindClass(GetPrivateModule(), wh.type._class.registered.name);
2441 EnumClassData enumeration = (EnumClassData)enumClass.data;
2443 for(item = enumeration.values.first; item; item = item.next)
2444 if((int)item.data == value)
2447 wh.value = CopyString(item.name);
2449 wh.value = CopyString($"Invalid Enum Value");
2450 result = (bool)atoi(exp.constant);
2452 else if(wh.type && (wh.type.kind == charType || (wh.type.kind == classType && wh.type._class &&
2453 wh.type._class.registered && !strcmp(wh.type._class.registered.fullName, "ecere::com::unichar"))) )
2460 if(exp.constant[0] == '\'')
2462 if((int)((byte *)exp.constant)[1] > 127)
2465 value = UTF8GetChar(exp.constant + 1, &nb);
2466 if(nb < 2) value = exp.constant[1];
2467 signedValue = value;
2471 signedValue = exp.constant[1];
2473 // Precomp Syntax error with boot strap here:
2474 byte b = (byte)(char)signedValue;
2475 value = (unichar) b;
2481 if(wh.type.kind == charType && wh.type.isSigned)
2483 signedValue = (int)(char)strtol(exp.constant, null, 0);
2485 // Precomp Syntax error with boot strap here:
2486 byte b = (byte)(char)signedValue;
2487 value = (unichar) b;
2492 value = (uint)strtoul(exp.constant, null, 0);
2493 signedValue = (int)value;
2497 UTF32toUTF8Len(&value, 1, charString, 5);
2499 snprintf(string, sizeof(string), "\'\\0' (0)");
2500 else if(value == '\t')
2501 snprintf(string, sizeof(string), "\'\\t' (%d)", value);
2502 else if(value == '\n')
2503 snprintf(string, sizeof(string), "\'\\n' (%d)", value);
2504 else if(value == '\r')
2505 snprintf(string, sizeof(string), "\'\\r' (%d)", value);
2506 else if(wh.type.kind == charType && wh.type.isSigned)
2507 snprintf(string, sizeof(string), "\'%s\' (%d)", charString, signedValue);
2508 else if(value > 256 || wh.type.kind != charType)
2510 if(value > 0x10FFFF || !GetCharCategory(value))
2511 snprintf(string, sizeof(string), $"Invalid Unicode Keypoint (0x%08X)", value);
2513 snprintf(string, sizeof(string), "\'%s\' (U+%04X)", charString, value);
2516 snprintf(string, sizeof(string), "\'%s\' (%d)", charString, value);
2517 string[sizeof(string)-1] = 0;
2519 wh.value = CopyString(string);
2524 wh.value = CopyString(exp.constant);
2525 result = (bool)atoi(exp.constant);
2531 wh.value = PrintHexUInt64(exp.address);
2532 result = (bool)exp.address;
2536 char tempString[256];
2537 if(exp.member.memberType == propertyMember)
2538 snprintf(watchmsg, sizeof(watchmsg), $"Missing property evaluation support for \"%s\"", wh.expression);
2540 snprintf(watchmsg, sizeof(watchmsg), $"Evaluation failed for \"%s\" of type \"%s\"", wh.expression,
2541 exp.type.OnGetString(tempString, null, null));
2547 snprintf(watchmsg, sizeof(watchmsg), $"Invalid expression: \"%s\"", wh.expression);
2548 if(exp) FreeExpression(exp);
2551 SetPrivateModule(backupPrivateModule);
2552 SetCurrentContext(backupContext);
2553 SetTopContext(backupContext);
2554 SetGlobalContext(backupContext);
2555 SetThisClass(backupThisClass);
2558 // wh.value = CopyString("No source file found for selected frame");
2560 watchmsg[sizeof(watchmsg)-1] = 0;
2562 wh.value = CopyString(watchmsg);
2564 ide.watchesView.UpdateWatch(wh);
2568 void EvaluateWatches()
2570 for(wh : ide.workspace.watches)
2574 char * ::GdbEvaluateExpression(char * expression)
2578 GdbCommand(false, "-data-evaluate-expression \"%s\"", expression);
2580 ide.outputView.debugBox.Logf("Debugger Error: GdbEvaluateExpression\n");
2584 // to be removed... use GdbReadMemory that returns a byte array instead
2585 char * ::GdbReadMemoryString(uint64 address, int size, char format, int rows, int cols)
2591 printf("GdbReadMemoryString called with size = 0!\n");
2593 // GdbCommand(false, "-data-read-memory 0x%08x %c, %d, %d, %d", address, format, size, rows, cols);
2594 if(GetRuntimePlatform() == win32)
2595 GdbCommand(false, "-data-read-memory 0x%016I64x %c, %d, %d, %d", address, format, size, rows, cols);
2597 GdbCommand(false, "-data-read-memory 0x%016llx %c, %d, %d, %d", address, format, size, rows, cols);
2599 ide.outputView.debugBox.Logf("Debugger Error: GdbReadMemoryString\n");
2603 byte * ::GdbReadMemory(uint64 address, int bytes)
2607 //GdbCommand(false, "-data-read-memory 0x%08x %c, 1, 1, %d", address, 'u', bytes);
2608 if(GetRuntimePlatform() == win32)
2609 GdbCommand(false, "-data-read-memory 0x%016I64x %c, 1, 1, %d", address, 'u', bytes);
2611 GdbCommand(false, "-data-read-memory 0x%016llx %c, 1, 1, %d", address, 'u', bytes);
2614 printf("GdbReadMemory called with bytes = 0!\n");
2617 ide.outputView.debugBox.Logf("Debugger Error: GdbReadMemory\n");
2618 else if(eval.result && strcmp(eval.result, "N/A"))
2620 byte * result = new byte[bytes];
2621 byte * string = eval.result;
2625 result[c++] = (byte)strtol(string, &string, 10);
2641 void EventHit(GdbDataStop stopItem)
2643 bool conditionMet = true;
2644 Breakpoint bp = bpHit;
2646 if(!bp && bpRunToCursor)
2650 GdbCommand(false, "-break-delete %d", bp.bp.number);
2655 if(bp.type == user && stopItem.frame.line && bp.line != stopItem.frame.line)
2657 bp.line = stopItem.frame.line;
2658 ide.breakpointsView.UpdateBreakpoint(bp.row);
2659 ide.workspace.Save();
2665 case internalWinMain:
2666 GdbBreakpointsInsert();
2667 if(userBreakOnInternBreak)
2669 userBreakOnInternBreak = false;
2670 // Why was SelectFrame missing here?
2671 SelectFrame(activeFrameLevel);
2672 GoToStackFrameLine(activeFrameLevel, true);
2673 ideMainFrame.Activate(); // TOFIX: ide.Activate() is not reliable (app inactive)
2677 GdbExecContinue(false);
2679 case internalModulesLoaded:
2681 GdbInsertInternalBreakpoint();
2682 GdbBreakpointsInsert();
2683 GdbExecContinue(false);
2685 case internalModuleLoad:
2686 GdbBreakpointsInsert();
2687 GdbExecContinue(false);
2692 conditionMet = ResolveWatch(bp.condition);
2694 if((bp.level == -1 || bp.level == frameCount-1) && conditionMet)
2699 ignoreBreakpoints = false;
2700 // Why was SelectFrame missing here?
2701 SelectFrame(activeFrameLevel);
2702 GoToStackFrameLine(activeFrameLevel, true);
2703 ideMainFrame.Activate(); // TOFIX: ide.Activate() is not reliable (app inactive)
2705 if(bp.type == BreakpointType::runToCursor)
2707 delete bpRunToCursor;
2708 bpRunToCursor = null;
2714 GdbExecContinue(false);
2718 GdbExecContinue(false);
2719 ide.breakpointsView.UpdateBreakpoint(bp.row);
2724 ide.outputView.debugBox.Logf("Debugger Error: Breakpoint hit could not match breakpoint instance\n");
2727 void GdbThreadExit()
2729 if(state != terminated)
2731 ChangeState(terminated);
2732 targetProcessId = 0;
2733 ClearBreakDisplay();
2737 serialSemaphore.Release();
2742 ide.outputView.debugBox.Logf($"Debugger Fatal Error: GDB lost\n");
2743 ide.outputView.debugBox.Logf($"Debugging stopped\n");
2746 //ChangeState(terminated);
2750 void GdbThreadMain(char * output)
2753 Array<char *> outTokens { minAllocSize = 50 };
2754 Array<char *> subTokens { minAllocSize = 50 };
2755 DebugListItem item { };
2756 DebugListItem item2 { };
2757 bool setWaitingForPID = false;
2759 #if defined(GDB_DEBUG_CONSOLE) || defined(GDB_DEBUG_GUI)
2760 #ifdef GDB_DEBUG_CONSOLE
2761 Log(output); Log("\n");
2763 #ifdef GDB_DEBUG_OUTPUT
2765 int len = strlen(output);
2773 for(c = 0; c < len / 1024; c++)
2775 strncpy(tmp, start, 1024);
2776 ide.outputView.gdbBox.Logf("out: %s\n", tmp);
2779 ide.outputView.gdbBox.Logf("out: %s\n", start);
2783 ide.outputView.gdbBox.Logf("out: %s\n", output);
2787 #ifdef GDB_DEBUG_CONSOLE
2788 strcpy(lastGdbOutput, output);
2790 #ifdef GDB_DEBUG_GUI
2791 if(ide.gdbDialog) ide.gdbDialog.AddOutput(output);
2798 if(strstr(output, "No debugging symbols found") || strstr(output, "(no debugging symbols found)"))
2801 ide.outputView.debugBox.Logf($"Target doesn't contain debug information!\n");
2807 if(TokenizeList(output, ',', outTokens) && !strcmp(outTokens[0], "^done"))
2809 //if(outTokens.count == 1)
2814 ChangeState(loaded);
2815 targetProcessId = 0;
2816 if(outTokens.count > 1 && TokenizeListItem(outTokens[1], item))
2818 if(!strcmp(item.name, "reason"))
2820 char * reason = item.value;
2821 StripQuotes(reason, reason);
2822 if(!strcmp(reason, "exited-normally") || !strcmp(reason, "exited") || !strcmp(reason, "exited-signalled"))
2825 if(outTokens.count > 2 && TokenizeListItem(outTokens[2], item2))
2827 StripQuotes(item2.value, item2.value);
2828 if(!strcmp(item2.name, "exit-code"))
2829 exitCode = item2.value;
2835 HandleExit(reason, exitCode);
2839 DebuggerProtocolUnknown("Unknown kill reply", item.name);
2842 HandleExit(null, null);
2845 if(outTokens.count > 1 && TokenizeListItem(outTokens[1], item))
2847 if(!strcmp(item.name, "bkpt"))
2849 sentBreakInsert = false;
2852 printf("problem\n");
2854 bpItem = GdbDataBreakpoint { };
2855 item.value = StripCurlies(item.value);
2856 TokenizeList(item.value, ',', subTokens);
2857 for(i = 0; i < subTokens.count; i++)
2859 if(TokenizeListItem(subTokens[i], item))
2861 StripQuotes(item.value, item.value);
2862 if(!strcmp(item.name, "number"))
2863 bpItem.number = atoi(item.value);
2864 else if(!strcmp(item.name, "type"))
2865 bpItem.type = CopyString(item.value);
2866 else if(!strcmp(item.name, "disp"))
2867 bpItem.disp = CopyString(item.value);
2868 else if(!strcmp(item.name, "enabled"))
2869 bpItem.enabled = (!strcmpi(item.value, "y"));
2870 else if(!strcmp(item.name, "addr"))
2871 bpItem.addr = CopyString(item.value);
2872 else if(!strcmp(item.name, "func"))
2873 bpItem.func = CopyString(item.value);
2874 else if(!strcmp(item.name, "file"))
2875 bpItem.file = item.value;
2876 else if(!strcmp(item.name, "line"))
2877 bpItem.line = atoi(item.value);
2878 else if(!strcmp(item.name, "at"))
2879 bpItem.at = CopyString(item.value);
2880 else if(!strcmp(item.name, "times"))
2881 bpItem.times = atoi(item.value);
2884 //breakType = bpValidation;
2885 //app.SignalEvent();
2886 subTokens.RemoveAll();
2888 else if(!strcmp(item.name, "BreakpointTable"))
2889 ide.outputView.debugBox.Logf("Debugger Error: Command reply BreakpointTable not handled\n");
2890 else if(!strcmp(item.name, "depth"))
2892 StripQuotes(item.value, item.value);
2893 frameCount = atoi(item.value);
2895 stackFrames.Free(Frame::Free);
2897 else if(!strcmp(item.name, "stack"))
2900 if(stackFrames.count)
2901 ide.callStackView.Logf("...\n");
2904 item.value = StripBrackets(item.value);
2905 TokenizeList(item.value, ',', subTokens);
2906 for(i = 0; i < subTokens.count; i++)
2908 if(TokenizeListItem(subTokens[i], item))
2910 if(!strcmp(item.name, "frame"))
2913 stackFrames.Add(frame);
2914 item.value = StripCurlies(item.value);
2915 ParseFrame(frame, item.value);
2916 if(frame.file && frame.from)
2917 DebuggerProtocolUnknown("Unexpected frame file and from members present", "");
2921 if(activeFrameLevel == -1)
2923 if(ide.projectView.IsModuleInProject(frame.file));
2925 if(frame.level != 0)
2927 //stopItem.frame = frame;
2928 breakType = selectFrame;
2931 activeFrame = frame;
2932 activeFrameLevel = frame.level;
2935 ide.callStackView.Logf("%3d ", frame.level);
2936 if(!strncmp(frame.func, "__ecereMethod_", strlen("__ecereMethod_")))
2937 ide.callStackView.Logf($"%s Method, %s:%d\n", &frame.func[strlen("__ecereMethod_")], (s = CopySystemPath(frame.file)), frame.line);
2938 else if(!strncmp(frame.func, "__ecereProp_", strlen("__ecereProp_")))
2939 ide.callStackView.Logf($"%s Property, %s:%d\n", &frame.func[strlen("__ecereProp_")], (s = CopySystemPath(frame.file)), frame.line);
2940 else if(!strncmp(frame.func, "__ecereConstructor_", strlen("__ecereConstructor_")))
2941 ide.callStackView.Logf($"%s Constructor, %s:%d\n", &frame.func[strlen("__ecereConstructor_")], (s = CopySystemPath(frame.file)), frame.line);
2942 else if(!strncmp(frame.func, "__ecereDestructor_", strlen("__ecereDestructor_")))
2943 ide.callStackView.Logf($"%s Destructor, %s:%d\n", &frame.func[strlen("__ecereDestructor_")], (s = CopySystemPath(frame.file)), frame.line);
2945 ide.callStackView.Logf($"%s Function, %s:%d\n", frame.func, (s = CopySystemPath(frame.file)), frame.line);
2950 ide.callStackView.Logf("%3d ", frame.level);
2955 ide.callStackView.Logf($"inside %s, %s\n", frame.func, (s = CopySystemPath(frame.from)));
2959 ide.callStackView.Logf("%s\n", frame.func);
2961 ide.callStackView.Logf($"unknown source\n");
2965 DebuggerProtocolUnknown("Unknown stack content", item.name);
2968 if(activeFrameLevel == -1)
2970 activeFrameLevel = 0;
2971 activeFrame = stackFrames.first;
2973 ide.callStackView.Home();
2975 subTokens.RemoveAll();
2977 /*else if(!strcmp(item.name, "frame"))
2980 item.value = StripCurlies(item.value);
2981 ParseFrame(&frame, item.value);
2983 else if(!strcmp(item.name, "thread-ids"))
2985 ide.threadsView.Clear();
2986 item.value = StripCurlies(item.value);
2987 TokenizeList(item.value, ',', subTokens);
2988 for(i = subTokens.count - 1; ; i--)
2990 if(TokenizeListItem(subTokens[i], item))
2992 if(!strcmp(item.name, "thread-id"))
2995 StripQuotes(item.value, item.value);
2996 value = atoi(item.value);
2997 ide.threadsView.Logf("%3d \n", value);
3000 DebuggerProtocolUnknown("Unknown threads content", item.name);
3005 ide.threadsView.Home();
3007 subTokens.RemoveAll();
3008 //if(!strcmp(outTokens[2], "number-of-threads"))
3010 else if(!strcmp(item.name, "new-thread-id"))
3012 StripQuotes(item.value, item.value);
3013 activeThread = atoi(item.value);
3015 else if(!strcmp(item.name, "value"))
3017 StripQuotes(item.value, item.value);
3018 eval.result = CopyString(item.value);
3019 eval.active = false;
3021 else if(!strcmp(item.name, "addr"))
3023 for(i = 2; i < outTokens.count; i++)
3025 if(TokenizeListItem(outTokens[i], item))
3027 if(!strcmp(item.name, "total-bytes"))
3029 StripQuotes(item.value, item.value);
3030 eval.bytes = atoi(item.value);
3032 else if(!strcmp(item.name, "next-row"))
3034 StripQuotes(item.value, item.value);
3035 eval.nextBlockAddress = _strtoui64(item.value, null, 0);
3037 else if(!strcmp(item.name, "memory"))
3041 //StripQuotes(item.value, item.value);
3042 item.value = StripBrackets(item.value);
3043 // this should be treated as a list...
3044 item.value = StripCurlies(item.value);
3045 TokenizeList(item.value, ',', subTokens);
3046 for(j = 0; j < subTokens.count; j++)
3048 if(TokenizeListItem(subTokens[j], item))
3050 if(!strcmp(item.name, "data"))
3052 item.value = StripBrackets(item.value);
3053 StripQuotes2(item.value, item.value);
3054 eval.result = CopyString(item.value);
3055 eval.active = false;
3059 subTokens.RemoveAll();
3064 else if(!strcmp(item.name, "source-path"))
3068 DebuggerProtocolUnknown("Unknown command reply", item.name);
3071 else if(!strcmp(outTokens[0], "^running"))
3073 waitingForPID = true;
3074 setWaitingForPID = true;
3076 else if(!strcmp(outTokens[0], "^exit"))
3078 ChangeState(terminated);
3079 // ide.outputView.debugBox.Logf("Exit\n");
3080 // ide.Update(null);
3082 serialSemaphore.Release();
3084 else if(!strcmp(outTokens[0], "^error"))
3088 sentBreakInsert = false;
3089 breakpointError = true;
3092 printf("problem\n");
3094 bpItem = GdbDataBreakpoint { };
3097 if(outTokens.count > 1 && TokenizeListItem(outTokens[1], item))
3099 if(!strcmp(item.name, "msg"))
3101 StripQuotes(item.value, item.value);
3104 eval.active = false;
3106 if(strstr(item.value, "No symbol") && strstr(item.value, "in current context"))
3107 eval.error = symbolNotFound;
3108 else if(strstr(item.value, "Cannot access memory at address"))
3109 eval.error = memoryCantBeRead;
3111 eval.error = unknown;
3113 else if(!strcmp(item.value, "Previous frame inner to this frame (corrupt stack?)"))
3116 else if(!strncmp(item.value, "Cannot access memory at address", 31))
3119 else if(!strcmp(item.value, "Cannot find bounds of current function"))
3121 ChangeState(stopped);
3122 gdbHandle.Printf("-exec-continue\n");
3124 else if(!strcmp(item.value, "ptrace: No such process."))
3126 ChangeState(loaded);
3127 targetProcessId = 0;
3129 else if(!strcmp(item.value, "Function \\\"WinMain\\\" not defined."))
3132 else if(!strcmp(item.value, "You can't do that without a process to debug."))
3134 ChangeState(loaded);
3135 targetProcessId = 0;
3137 else if(strstr(item.value, "No such file or directory."))
3139 ChangeState(loaded);
3140 targetProcessId = 0;
3142 else if(strstr(item.value, "During startup program exited with code "))
3144 ChangeState(loaded);
3145 targetProcessId = 0;
3150 if(strlen(item.value) < MAX_F_STRING)
3153 ide.outputView.debugBox.Logf("GDB: %s\n", (s = CopyUnescapedString(item.value)));
3157 ide.outputView.debugBox.Logf("GDB: %s\n", item.value);
3163 DebuggerProtocolUnknown("Unknown error content", item.name);
3166 DebuggerProtocolUnknown("Unknown result-record", outTokens[0]);
3168 outTokens.RemoveAll();
3171 DebuggerProtocolUnknown("Unknown status-async-output", outTokens[0]);
3174 if(TokenizeList(output, ',', outTokens) && !strcmp(outTokens[0], "=thread-group-created")) //=thread-group-created,id="7611"
3176 else if(!strcmp(outTokens[0], "=thread-created")) //=thread-created,id="1",group-id="7611"
3178 else if(!strcmp(outTokens[0], "=library-loaded")) //=library-loaded,id="/lib/ld-linux.so.2",target-name="/lib/ld-linux.so.2",host-name="/lib/ld-linux.so.2",symbols-loaded="0"
3181 DebuggerProtocolUnknown("Unknown notify-async-output", outTokens[0]);
3182 outTokens.RemoveAll();
3186 if(TokenizeList(output, ',', outTokens))
3188 if(!strcmp(outTokens[0],"*running"))
3190 waitingForPID = true;
3191 setWaitingForPID = true;
3193 else if(!strcmp(outTokens[0], "*stopped"))
3196 ChangeState(stopped);
3198 for(tk = 1; tk < outTokens.count; tk++)
3200 if(TokenizeListItem(outTokens[tk], item))
3202 if(!strcmp(item.name, "reason"))
3204 char * reason = item.value;
3205 StripQuotes(reason, reason);
3206 if(!strcmp(reason, "exited-normally") || !strcmp(reason, "exited") || !strcmp(reason, "exited-signalled"))
3209 if(outTokens.count > tk+1 && TokenizeListItem(outTokens[tk+1], item2))
3212 StripQuotes(item2.value, item2.value);
3213 if(!strcmp(item2.name, "exit-code"))
3214 exitCode = item2.value;
3220 HandleExit(reason, exitCode);
3222 else if(!strcmp(reason, "breakpoint-hit"))
3226 printf("problem\n");
3228 stopItem = GdbDataStop { };
3230 for(i = tk+1; i < outTokens.count; i++)
3232 TokenizeListItem(outTokens[i], item);
3233 StripQuotes(item.value, item.value);
3234 if(!strcmp(item.name, "bkptno"))
3235 stopItem.bkptno = atoi(item.value);
3236 else if(!strcmp(item.name, "thread-id"))
3237 stopItem.threadid = atoi(item.value);
3238 else if(!strcmp(item.name, "frame"))
3240 item.value = StripCurlies(item.value);
3241 ParseFrame(stopItem.frame, item.value);
3244 DebuggerProtocolUnknown("Unknown breakpoint hit item name", item.name);
3249 else if(!strcmp(reason, "end-stepping-range"))
3253 printf("problem\n");
3255 stopItem = GdbDataStop { };
3257 for(i = tk+1; i < outTokens.count; i++)
3259 TokenizeListItem(outTokens[i], item);
3260 StripQuotes(item.value, item.value);
3261 if(!strcmp(item.name, "thread-id"))
3262 stopItem.threadid = atoi(item.value);
3263 else if(!strcmp(item.name, "frame"))
3265 item.value = StripCurlies(item.value);
3266 ParseFrame(stopItem.frame, item.value);
3268 else if(!strcmp(item.name, "reason"))
3270 else if(!strcmp(item.name, "bkptno"))
3273 DebuggerProtocolUnknown("Unknown end of stepping range item name", item.name);
3279 else if(!strcmp(reason, "function-finished"))
3283 printf("problem\n");
3285 stopItem = GdbDataStop { };
3286 stopItem.reason = CopyString(reason);
3288 for(i = tk+1; i < outTokens.count; i++)
3290 TokenizeListItem(outTokens[i], item);
3291 StripQuotes(item.value, item.value);
3292 if(!strcmp(item.name, "thread-id"))
3293 stopItem.threadid = atoi(item.value);
3294 else if(!strcmp(item.name, "frame"))
3296 item.value = StripCurlies(item.value);
3297 ParseFrame(stopItem.frame, item.value);
3299 else if(!strcmp(item.name, "gdb-result-var"))
3300 stopItem.gdbResultVar = CopyString(item.value);
3301 else if(!strcmp(item.name, "return-value"))
3302 stopItem.returnValue = CopyString(item.value);
3304 DebuggerProtocolUnknown("Unknown function finished item name", item.name);
3307 event = functionEnd;
3310 else if(!strcmp(reason, "signal-received"))
3314 printf("problem\n");
3316 stopItem = GdbDataStop { };
3317 stopItem.reason = CopyString(reason);
3319 for(i = tk+1; i < outTokens.count; i++)
3321 TokenizeListItem(outTokens[i], item);
3322 StripQuotes(item.value, item.value);
3323 if(!strcmp(item.name, "signal-name"))
3324 stopItem.name = CopyString(item.value);
3325 else if(!strcmp(item.name, "signal-meaning"))
3326 stopItem.meaning = CopyString(item.value);
3327 else if(!strcmp(item.name, "thread-id"))
3328 stopItem.threadid = atoi(item.value);
3329 else if(!strcmp(item.name, "frame"))
3331 item.value = StripCurlies(item.value);
3332 ParseFrame(stopItem.frame, item.value);
3335 DebuggerProtocolUnknown("Unknown signal reveived item name", item.name);
3337 if(!strcmp(stopItem.name, "SIGTRAP"))
3356 else if(!strcmp(reason, "watchpoint-trigger"))
3357 DebuggerProtocolUnknown("Reason watchpoint trigger not handled", "");
3358 else if(!strcmp(reason, "read-watchpoint-trigger"))
3359 DebuggerProtocolUnknown("Reason read watchpoint trigger not handled", "");
3360 else if(!strcmp(reason, "access-watchpoint-trigger"))
3361 DebuggerProtocolUnknown("Reason access watchpoint trigger not handled", "");
3362 else if(!strcmp(reason, "watchpoint-scope"))
3363 DebuggerProtocolUnknown("Reason watchpoint scope not handled", "");
3364 else if(!strcmp(reason, "location-reached"))
3365 DebuggerProtocolUnknown("Reason location reached not handled", "");
3367 DebuggerProtocolUnknown("Unknown reason", reason);
3375 DebuggerProtocolUnknown("Unknown exec-async-output", outTokens[0]);
3376 outTokens.RemoveAll();
3379 if(!strcmpi(output, "(gdb) "))
3383 char exeFile[MAX_LOCATION];
3384 int oldProcessID = targetProcessId;
3385 GetLastDirectory(targetFile, exeFile);
3389 targetProcessId = Process_GetChildExeProcessId(gdbProcessId, exeFile);
3390 if(targetProcessId || gdbHandle.Peek()) break;
3395 ChangeState(running);
3396 else if(!oldProcessID)
3398 ide.outputView.debugBox.Logf($"Debugger Error: No target process ID\n");
3399 // TO VERIFY: The rest of this block has not been thoroughly tested in this particular location
3400 gdbHandle.Printf("-gdb-exit\n");
3402 ChangeState(terminated); //loaded;
3407 for(bp : ide.workspace.breakpoints)
3408 bp.inserted = false;
3411 bp.inserted = false;
3413 bpRunToCursor.inserted = false;
3415 ide.outputView.debugBox.Logf($"Debugging stopped\n");
3416 ClearBreakDisplay();
3418 #if defined(__unix__)
3419 if(FileExists(progFifoPath)) //fileCreated)
3421 progThread.terminate = true;
3424 fifoFile.CloseInput();
3431 DeleteFile(progFifoPath);
3432 progFifoPath[0] = '\0';
3439 serialSemaphore.Release();
3442 DebuggerProtocolUnknown($"Unknown prompt", output);
3446 if(!strncmp(output, "&\"warning:", 10))
3449 content = strstr(output, "\"");
3450 StripQuotes(content, content);
3451 content = strstr(content, ":");
3457 ide.outputView.debugBox.LogRaw((s = CopyUnescapedString(content)));
3464 DebuggerProtocolUnknown($"Unknown output", output);
3466 if(!setWaitingForPID)
3467 waitingForPID = false;
3468 setWaitingForPID = false;
3476 void RunToCursorPrepare(char * absoluteFilePath, char * relativeFilePath, int lineNumber)
3480 //bpRunToCursor.Free();
3481 bpRunToCursor = Breakpoint { };
3484 bpRunToCursor = Breakpoint { };
3486 if(absoluteFilePath)
3487 bpRunToCursor.absoluteFilePath = CopyString(absoluteFilePath);
3488 if(relativeFilePath)
3489 bpRunToCursor.relativeFilePath = CopyString(relativeFilePath);
3490 bpRunToCursor.line = lineNumber;
3491 bpRunToCursor.type = runToCursor;
3492 bpRunToCursor.enabled = true;
3493 bpRunToCursor.condition = null;
3494 bpRunToCursor.ignore = 0;
3495 bpRunToCursor.level = -1;
3498 ExpressionType ::DebugEvalExpTypeError(char * result)
3504 case symbolNotFound:
3505 return symbolErrorExp;
3506 case memoryCantBeRead:
3507 return memoryErrorExp;
3509 return unknownErrorExp;
3512 char * ::EvaluateExpression(char * expression, ExpressionType * error)
3515 if(ide.projectView && ide.debugger.state == stopped)
3517 result = GdbEvaluateExpression(expression);
3518 *error = DebugEvalExpTypeError(result);
3523 *error = noDebuggerErrorExp;
3528 char * ::ReadMemory(uint64 address, int size, char format, ExpressionType * error)
3531 char * result = GdbReadMemoryString(address, size, format, 1, 1);
3532 if(!result || !strcmp(result, "N/A"))
3533 *error = memoryErrorExp;
3535 *error = DebugEvalExpTypeError(result);
3540 class GdbThread : Thread
3546 static char output[4096];
3547 Array<char> dynamicBuffer { minAllocSize = 4096 };
3548 DualPipe oldGdbHandle = gdbHandle;
3549 incref oldGdbHandle;
3552 while(debugger.state != terminated && gdbHandle && !gdbHandle.Eof())
3556 result = gdbHandle.Read(output, 1, sizeof(output));
3558 if(debugger.state == terminated || !gdbHandle || gdbHandle.Eof())
3565 for(c = 0; c<result; c++)
3567 if(output[c] == '\n')
3569 int pos = dynamicBuffer.size;
3570 dynamicBuffer.size += c - start;
3571 memcpy(&dynamicBuffer[pos], output + start, c - start);
3572 if(dynamicBuffer.count && dynamicBuffer[dynamicBuffer.count - 1] != '\r')
3573 // COMMENTED OUT DUE TO ISSUE #135, FIXED
3574 //if(dynamicBuffer.array[dynamicBuffer.count - 1] != '\r')
3575 dynamicBuffer.size++;
3576 dynamicBuffer[dynamicBuffer.count - 1] = '\0';
3578 // printf("%s\n", dynamicBuffer.array);
3580 debugger.GdbThreadMain(&dynamicBuffer[0]);
3581 dynamicBuffer.size = 0;
3587 int pos = dynamicBuffer.size;
3588 dynamicBuffer.size += c - start;
3589 memcpy(&dynamicBuffer[pos], output + start, c - start);
3595 printf("Got end of file from GDB!\n");
3599 delete dynamicBuffer;
3600 //if(oldGdbHandle == gdbHandle)
3601 debugger.GdbThreadExit();
3602 delete oldGdbHandle;
3608 static define createFIFOMsg = $"err: Unable to create FIFO %s\n";
3609 static define openFIFOMsg = $"err: Unable to open FIFO %s for read\n";
3611 #if defined(__unix__)
3616 #include <sys/types.h>
3621 class ProgramThread : Thread
3627 bool fileCreated = false;
3629 static char output[1000];
3632 /*if(!mkfifo(progFifoPath, mask))
3639 ide.outputView.debugBox.Logf($"err: Unable to create FIFO %s\n", progFifoPath);
3643 if(FileExists(progFifoPath)) //fileCreated)
3645 fifoFile = FileOpen(progFifoPath, read);
3649 ide.outputView.debugBox.Logf(openFIFOMsg, progFifoPath);
3654 fd = fileno((FILE *)fifoFile.input);
3655 //fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
3659 while(!terminate && fifoFile && !fifoFile.Eof())
3662 struct timeval time;
3670 selectResult = select(fd + 1, &rs, null, null, &time);
3671 if(FD_ISSET(fd, &rs))
3673 int result = (int)read(fd, output, sizeof(output)-1);
3674 if(!result || (result < 0 && errno != EAGAIN))
3678 output[result] = '\0';
3679 if(strcmp(output,"&\"warning: GDB: Failed to set controlling terminal: Invalid argument\\n\"\n"))
3682 ide.outputView.debugBox.Log(output);
3691 //fifoFile.CloseInput();
3694 ide.outputView.debugBox.Log("\n");
3698 if(FileExists(progFifoPath)) //fileCreated)
3700 DeleteFile(progFifoPath);
3701 progFifoPath[0] = '\0';
3709 class Argument : struct
3711 Argument prev, next;
3727 class Frame : struct
3736 property char * from { set { delete from; if(value) from = CopyUnescapedUnixPath(value); } }
3738 property char * file { set { delete file; if(value) file = CopyUnescapedUnixPath(value); } }
3739 char * absoluteFile;
3748 delete absoluteFile;
3749 args.Free(Argument::Free);
3758 class GdbDataStop : struct
3775 char * gdbResultVar;
3785 if(!strcmp(reason, "signal-received"))
3790 else if(!strcmp(reason, "function-finished"))
3792 delete gdbResultVar;
3797 if(frame) frame.Free();
3806 class GdbDataBreakpoint : struct
3815 property char * file { set { delete file; if(value) file = CopyUnescapedUnixPath(value); } }
3830 ~GdbDataBreakpoint()
3836 class Breakpoint : struct
3840 char * relativeFilePath;
3841 char * absoluteFilePath;
3850 BreakpointType type;
3853 GdbDataBreakpoint bp;
3855 char * LocationToString()
3857 char location[MAX_LOCATION+20];
3858 snprintf(location, sizeof(location), "%s:%d", relativeFilePath, line);
3859 location[sizeof(location)-1] = 0;
3860 #if defined(__WIN32__)
3861 ChangeCh(location, '/', '\\');
3863 return CopyString(location);
3868 if(relativeFilePath && relativeFilePath[0])
3870 f.Printf(" * %d,%d,%d,%d,%s\n", enabled ? 1 : 0, ignore, level, line, relativeFilePath);
3872 f.Printf(" ~ %s\n", condition.expression);
3881 delete relativeFilePath;
3882 delete absoluteFilePath;
3892 class Watch : struct
3903 f.Printf(" ~ %s\n", expression);
3927 class DebugListItem : struct
3933 struct DebugEvaluationData
3938 uint64 nextBlockAddress;
3940 DebuggerEvaluationError error;
3943 class CodeLocation : struct
3946 char * absoluteFile;
3949 CodeLocation ::ParseCodeLocation(char * location)
3953 char * colon = null;
3955 char loc[MAX_LOCATION];
3956 strcpy(loc, location);
3957 for(temp = loc; temp = strstr(temp, ":"); temp++)
3965 int line = atoi(colon);
3968 CodeLocation codloc { line = line };
3969 codloc.file = CopyString(loc);
3970 codloc.absoluteFile = ide.workspace.GetAbsolutePathFromRelative(loc);
3982 delete absoluteFile;