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, false);
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, false);
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*4];
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 GdbInsertInternalBreakpoints()
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;
1663 GdbCommand(false, "-break-delete %d", bp.bp.number);
1664 bp.inserted = false;
1666 //check here (reply form -break-delete, returns bpitem?)
1669 for(bp : ide.workspace.breakpoints)
1672 GdbCommand(false, "-break-delete %d", bp.bp.number);
1673 bp.inserted = false;
1675 //check here (reply form -break-delete, returns bpitem?)
1678 if(deleteRunToCursor && bpRunToCursor)
1680 GdbCommand(false, "-break-delete %d", bpRunToCursor.bp.number);
1681 bpRunToCursor.inserted = false;
1682 bpRunToCursor.bp = bpItem;
1683 //check here (reply form -break-delete, returns bpitem?)
1692 stackFrames.Free(Frame::Free);
1693 GdbCommand(false, "-stack-info-depth");
1695 GdbCommand(false, "-stack-info-depth 192");
1696 if(frameCount && frameCount <= 192)
1697 GdbCommand(false, "-stack-list-frames 0 %d", Min(frameCount-1, 191));
1700 GdbCommand(false, "-stack-list-frames 0 %d", Min(frameCount-1, 95));
1701 GdbCommand(false, "-stack-list-frames %d %d", Max(frameCount - 96, 96), frameCount - 1);
1703 GdbCommand(false, "");
1710 char escaped[MAX_LOCATION];
1711 strescpy(escaped, targetFile);
1712 GdbCommand(false, "file \"%s\"", escaped); //GDB/MI Missing Implementation -symbol-file, -target-attach
1717 for(prj : ide.workspace.projects)
1719 if(prj == ide.workspace.projects.firstIterator.data)
1722 //PrintLn("THIS: ", (String)prj.topNode.path);
1723 GdbCommand(false, "-environment-directory \"%s\"", prj.topNode.path);
1724 //GdbCommand(false, ""); // why this empty GDB command
1727 for(dir : ide.workspace.sourceDirs)
1729 GdbCommand(false, "-environment-directory \"%s\"", dir);
1730 //GdbCommand(false, ""); // why this empty GDB command
1732 GdbInsertInternalBreakpoints();
1738 void GdbTargetRelease()
1742 GdbBreakpointsDelete(true);
1743 GdbCommand(false, "file"); //GDB/MI Missing Implementation -target-detach
1749 void GdbDebugBreak(bool internal)
1754 breakType = DebuggerAction::internal;
1756 if(ide) ide.Update(null);
1758 if(Process_Break(targetProcessId)) //GdbCommand(false, "-exec-interrupt");
1759 serialSemaphore.Wait();
1762 ChangeState(loaded);
1763 targetProcessId = 0;
1768 ide.outputView.debugBox.Logf("Debugger Error: GdbDebugBreak with not target id should never happen\n");
1775 ShowDebuggerViews();
1776 GdbCommand(true, "-exec-run");
1779 void GdbExecContinue(bool focus)
1782 GdbCommand(focus, "-exec-continue");
1788 GdbCommand(true, "-exec-next");
1794 GdbCommand(true, "-exec-step");
1797 void GdbExecFinish()
1800 GdbCommand(true, "-exec-finish");
1803 void GdbExecCommon()
1805 ClearBreakDisplay();
1806 GdbInsertInternalBreakpoints();
1807 GdbBreakpointsInsert();
1810 #ifdef GDB_DEBUG_GUI
1811 void SendGDBCommand(char * command)
1813 DebuggerState oldState = state;
1818 GdbDebugBreak(true);
1821 GdbCommand(false, command);
1824 if(oldState == running)
1825 GdbExecContinue(false);
1829 void ClearBreakDisplay()
1832 activeFrameLevel = -1;
1843 stackFrames.Free(Frame::Free);
1844 WatchesCodeEditorLinkRelease();
1845 ide.callStackView.Clear();
1846 ide.threadsView.Clear();
1853 GdbCommand(false, "-interpreter-exec console \"kill\""); // should use -exec-abort -- GDB/MI implementation incomplete
1857 bool GdbInit(CompilerConfig compiler, ProjectConfig config, int bitDepth)
1860 char oldDirectory[MAX_LOCATION];
1861 char tempPath[MAX_LOCATION];
1862 char command[MAX_LOCATION];
1863 Project project = ide.project;
1864 DirExpression targetDirExp = project.GetTargetDir(compiler, config, bitDepth);
1865 PathBackup pathBackup { };
1867 if(currentCompiler != compiler)
1869 delete currentCompiler;
1870 currentCompiler = compiler;
1871 incref currentCompiler;
1874 this.bitDepth = bitDepth;
1876 ChangeState(loaded);
1878 sentBreakInsert = false;
1879 breakpointError = false;
1883 //breakpointsInserted = false;
1885 ide.outputView.ShowClearSelectTab(debug);
1886 ide.outputView.debugBox.Logf($"Starting debug mode\n");
1888 #ifdef GDB_DEBUG_CONSOLE
1889 Log("Starting GDB"); Log("\n");
1891 #ifdef GDB_DEBUG_OUTPUT
1892 ide.outputView.gdbBox.Logf("run: Starting GDB\n");
1895 strcpy(tempPath, ide.workspace.projectDir);
1896 PathCatSlash(tempPath, targetDirExp.dir);
1898 targetDir = CopyString(tempPath);
1899 project.CatTargetFileName(tempPath, compiler, config);
1901 targetFile = CopyString(tempPath);
1903 GetWorkingDir(oldDirectory, MAX_LOCATION);
1904 if(ide.workspace.debugDir && ide.workspace.debugDir[0])
1906 char temp[MAX_LOCATION];
1907 strcpy(temp, ide.workspace.projectDir);
1908 PathCatSlash(temp, ide.workspace.debugDir);
1909 ChangeWorkingDir(temp);
1912 ChangeWorkingDir(ide.workspace.projectDir);
1914 ide.SetPath(true, compiler, config, bitDepth);
1916 // TODO: This pollutes the environment, but at least it works
1917 // It shouldn't really affect the IDE as the PATH gets restored and other variables set for testing will unlikely cause problems
1918 // What is the proper solution for this? DualPipeOpenEnv?
1919 // gdb set environment commands don't seem to take effect
1920 for(e : ide.workspace.environmentVars)
1922 SetEnvironment(e.name, e.string);
1926 (compiler.targetPlatform == win32 && bitDepth == 64) ? "x86_64-w64-mingw32-gdb" :
1927 (compiler.targetPlatform == win32 && bitDepth == 32) ? "i686-w64-mingw32-gdb" :
1929 strcat(command, " -n -silent --interpreter=mi2"); //-async //\"%s\"
1931 gdbHandle = DualPipeOpen(PipeOpenMode { output = 1, error = 2, input = 1 }, command);
1934 ide.outputView.debugBox.Logf($"Debugger Fatal Error: Couldn't start GDB\n");
1942 gdbProcessId = gdbHandle.GetProcessID();
1945 ide.outputView.debugBox.Logf($"Debugger Fatal Error: Couldn't get GDB process ID\n");
1951 serialSemaphore.Wait();
1956 //ChangeState(terminated);
1962 #if defined(__unix__)
1964 CreateTemporaryDir(progFifoDir, "ecereide");
1965 strcpy(progFifoPath, progFifoDir);
1966 PathCat(progFifoPath, "ideprogfifo");
1967 if(!mkfifo(progFifoPath, 0600))
1969 //fileCreated = true;
1974 ide.outputView.debugBox.Logf(createFIFOMsg, progFifoPath);
1979 progThread.terminate = false;
1980 progThread.Create();
1983 #if defined(__WIN32__)
1984 GdbCommand(false, "-gdb-set new-console on");
1987 GdbCommand(false, "-gdb-set verbose off");
1988 //GdbCommand(false, "-gdb-set exec-done-display on");
1989 GdbCommand(false, "-gdb-set step-mode off");
1990 GdbCommand(false, "-gdb-set unwindonsignal on");
1991 //GdbCommand(false, "-gdb-set shell on");
1992 GdbCommand(false, "set print elements 992");
1993 GdbCommand(false, "-gdb-set backtrace limit 100000");
1995 #if defined(__unix__)
1996 GdbCommand(false, "-inferior-tty-set %s", progFifoPath);
1999 GdbCommand(false, "-gdb-set args %s", ide.workspace.commandLineArgs ? ide.workspace.commandLineArgs : "");
2001 for(e : ide.workspace.environmentVars)
2003 GdbCommand(false, "set environment %s=%s", e.name, e.string);
2010 ChangeWorkingDir(oldDirectory);
2016 delete targetDirExp;
2022 if(gdbHandle && gdbProcessId)
2024 GdbCommand(false, "-gdb-exit");
2039 ChangeState(terminated); // this state change seems to be superfluous, is it safety for something?
2043 for(bp : ide.workspace.breakpoints)
2044 bp.inserted = false;
2046 bp.inserted = false;
2048 bpRunToCursor.inserted = false;
2050 ide.outputView.debugBox.Logf($"Debugging stopped\n");
2051 ClearBreakDisplay();
2054 #if defined(__unix__)
2055 if(FileExists(progFifoPath)) //fileCreated)
2057 progThread.terminate = true;
2060 fifoFile.CloseInput();
2066 DeleteFile(progFifoPath);
2067 progFifoPath[0] = '\0';
2073 void WatchesCodeEditorLinkInit()
2076 char tempPath[MAX_LOCATION];
2077 char path[MAX_LOCATION];
2079 //void MakeFilePathProjectRelative(char * path, char * relativePath)
2080 if(!ide.projectView.GetRelativePath(activeFrame.file, tempPath))
2081 strcpy(tempPath, activeFrame.file);
2083 strcpy(path, ide.workspace.projectDir);
2084 PathCat(path, tempPath);
2085 codeEditor = (CodeEditor)ide.OpenFile(path, Normal, false, null, no, normal, false);
2088 for(srcDir : ide.workspace.sourceDirs)
2090 strcpy(path, srcDir);
2091 PathCat(path, tempPath);
2092 codeEditor = (CodeEditor)ide.OpenFile(path, Normal, false, null, no, normal, false);
2093 if(codeEditor) break;
2098 if(activeFrame && !activeFrame.absoluteFile && activeFrame.file)
2099 activeFrame.absoluteFile = ide.workspace.GetAbsolutePathFromRelative(activeFrame.file);
2100 if(!activeFrame || !activeFrame.absoluteFile)
2103 codeEditor = (CodeEditor)ide.OpenFile(activeFrame.absoluteFile, normal, false, null, no, normal, false);
2106 codeEditor.inUseDebug = true;
2109 //watchesInit = true;
2112 void WatchesCodeEditorLinkRelease()
2118 codeEditor.inUseDebug = false;
2119 if(!codeEditor.visible)
2120 codeEditor.Destroy(0);
2126 bool ResolveWatch(Watch wh)
2128 bool result = false;
2141 char watchmsg[MAX_F_STRING];
2142 if(state == stopped && !codeEditor)
2143 wh.value = CopyString($"No source file found for selected frame");
2144 //if(codeEditor && state == stopped || state != stopped)
2147 Module backupPrivateModule;
2148 Context backupContext;
2149 Class backupThisClass;
2153 backupPrivateModule = GetPrivateModule();
2154 backupContext = GetCurrentContext();
2155 backupThisClass = GetThisClass();
2158 SetPrivateModule(codeEditor.privateModule);
2159 SetCurrentContext(codeEditor.globalContext);
2160 SetTopContext(codeEditor.globalContext);
2161 SetGlobalContext(codeEditor.globalContext);
2162 SetGlobalData(&codeEditor.globalData);
2165 exp = ParseExpressionString(wh.expression);
2167 if(exp && !parseError)
2169 if(GetPrivateModule())
2172 DebugFindCtxTree(codeEditor.ast, activeFrame.line, 0);
2173 ProcessExpressionType(exp);
2175 wh.type = exp.expType;
2178 DebugComputeExpression(exp);
2180 /*if(exp.hasAddress)
2182 char temp[MAX_F_STRING];
2183 sprintf(temp, "0x%x", exp.address);
2184 wh.address = CopyString(temp);
2185 // wh.address = CopyStringf("0x%x", exp.address);
2190 Type dataType = exp.expType;
2193 char temp[MAX_F_STRING];
2194 switch(dataType.kind)
2197 sprintf(temp, "%i", exp.val.c);
2200 sprintf(temp, "%i", exp.val.s);
2205 sprintf(temp, "%i", exp.val.i);
2208 sprintf(temp, "%i", exp.val.i64);
2211 sprintf(temp, "%i", exp.val.p);
2216 long v = (long)exp.val.f;
2217 sprintf(temp, "%i", v);
2222 long v = (long)exp.val.d;
2223 sprintf(temp, "%i", v);
2228 wh.intVal = CopyString(temp);
2229 switch(dataType.kind)
2232 sprintf(temp, "0x%x", exp.val.c);
2235 sprintf(temp, "0x%x", exp.val.s);
2239 sprintf(temp, "0x%x", exp.val.i);
2242 sprintf(temp, "0x%x", exp.val.i64);
2245 sprintf(temp, "0x%x", exp.val.i64);
2248 sprintf(temp, "0x%x", exp.val.p);
2253 long v = (long)exp.val.f;
2254 sprintf(temp, "0x%x", v);
2259 long v = (long)exp.val.d;
2260 sprintf(temp, "0x%x", v);
2265 wh.hexVal = CopyString(temp);
2266 switch(dataType.kind)
2269 sprintf(temp, "0o%o", exp.val.c);
2272 sprintf(temp, "0o%o", exp.val.s);
2276 sprintf(temp, "0o%o", exp.val.i);
2279 sprintf(temp, "0o%o", exp.val.i64);
2282 sprintf(temp, "0o%o", exp.val.i64);
2285 sprintf(temp, "0o%o", exp.val.p);
2290 long v = (long)exp.val.f;
2291 sprintf(temp, "0o%o", v);
2296 long v = (long)exp.val.d;
2297 sprintf(temp, "0o%o", v);
2302 wh.octVal = CopyString(temp);
2305 // WHATS THIS HERE ?
2306 if(exp.type == constantExp && exp.constant)
2307 wh.constant = CopyString(exp.constant);
2313 case symbolErrorExp:
2314 snprintf(watchmsg, sizeof(watchmsg), $"Symbol \"%s\" not found", exp.identifier.string);
2316 case structMemberSymbolErrorExp:
2317 // todo get info as in next case (ExpClassMemberSymbolError)
2318 snprintf(watchmsg, sizeof(watchmsg), $"Error: Struct member not found for \"%s\"", wh.expression);
2320 case classMemberSymbolErrorExp:
2323 Expression memberExp = exp.member.exp;
2324 Identifier memberID = exp.member.member;
2325 Type type = memberExp.expType;
2328 _class = (memberID && memberID.classSym) ? memberID.classSym.registered : ((type.kind == classType && type._class) ? type._class.registered : null);
2331 char string[256] = "";
2333 PrintTypeNoConst(type, string, false, true);
2334 classSym = FindClass(string);
2335 _class = classSym ? classSym.registered : null;
2338 snprintf(watchmsg, sizeof(watchmsg), $"Member \"%s\" not found in class \"%s\"", memberID ? memberID.string : "", _class.name);
2340 snprintf(watchmsg, sizeof(watchmsg), "Member \"%s\" not found in unregistered class? (Should never get this message)", memberID ? memberID.string : "");
2343 snprintf(watchmsg, sizeof(watchmsg), "Member \"%s\" not found in no type? (Should never get this message)", memberID ? memberID.string : "");
2346 case memoryErrorExp:
2347 // Need to ensure when set to memoryErrorExp, constant is set
2348 snprintf(watchmsg, sizeof(watchmsg), $"Memory can't be read at %s", /*(exp.type == constantExp) ? */exp.constant /*: null*/);
2350 case dereferenceErrorExp:
2351 snprintf(watchmsg, sizeof(watchmsg), $"Dereference failure for \"%s\"", wh.expression);
2353 case unknownErrorExp:
2354 snprintf(watchmsg, sizeof(watchmsg), $"Unknown error for \"%s\"", wh.expression);
2356 case noDebuggerErrorExp:
2357 snprintf(watchmsg, sizeof(watchmsg), $"Debugger required for symbol evaluation in \"%s\"", wh.expression);
2359 case debugStateErrorExp:
2360 snprintf(watchmsg, sizeof(watchmsg), $"Incorrect debugger state for symbol evaluation in \"%s\"", wh.expression);
2363 snprintf(watchmsg, sizeof(watchmsg), $"Null type for \"%s\"", wh.expression);
2367 // Temporary Code for displaying Strings
2368 if((exp.expType && ((exp.expType.kind == pointerType ||
2369 exp.expType.kind == arrayType) && exp.expType.type.kind == charType)) ||
2370 (wh.type && wh.type.kind == classType && wh.type._class &&
2371 wh.type._class.registered && wh.type._class.registered.type == normalClass &&
2372 !strcmp(wh.type._class.registered.name, "String")))
2375 if(exp.expType.kind != arrayType || exp.hasAddress)
2381 //char temp[MAX_F_STRING * 32];
2383 ExpressionType evalError = dummyExp;
2384 /*if(exp.expType.kind == arrayType)
2385 sprintf(temp, "(char*)0x%x", exp.address);
2387 sprintf(temp, "(char*)%s", exp.constant);*/
2389 //evaluation = Debugger::EvaluateExpression(temp, &evalError);
2390 // address = strtoul(exp.constant, null, 0);
2391 address = _strtoui64(exp.constant, null, 0);
2392 //printf("%x\n", address);
2393 // snprintf(value, sizeof(value), "0x%08x ", address);
2395 if(address > 0xFFFFFFFFLL)
2396 snprintf(value, sizeof(value), (GetRuntimePlatform() == win32) ? "0x%016I64x " : "0x%016llx ", address);
2398 snprintf(value, sizeof(value), (GetRuntimePlatform() == win32) ? "0x%08I64x " : "0x%08llx ", address);
2399 value[sizeof(value)-1] = 0;
2402 strcat(value, $"Null string");
2406 len = strlen(value);
2408 while(!string && size > 2)
2410 string = GdbReadMemory(address, size);
2413 if(string && string[0])
2416 if(UTF8Validate(string))
2421 for(c = 0; (ch = string[c]) && c<4096; c++)
2424 value[len++] = '\0';
2429 ISO8859_1toUTF8(string, value + len, 4096 - len - 30);
2430 strcat(value, ") (ISO8859-1)");
2437 strcat(value, $"Empty string");
2441 strcat(value, $"Couldn't read memory");
2443 wh.value = CopyString(value);
2446 else if(wh.type && wh.type.kind == classType && wh.type._class &&
2447 wh.type._class.registered && wh.type._class.registered.type == enumClass)
2449 uint64 value = strtoul(exp.constant, null, 0);
2450 Class enumClass = eSystem_FindClass(GetPrivateModule(), wh.type._class.registered.name);
2451 EnumClassData enumeration = (EnumClassData)enumClass.data;
2453 for(item = enumeration.values.first; item; item = item.next)
2454 if((int)item.data == value)
2457 wh.value = CopyString(item.name);
2459 wh.value = CopyString($"Invalid Enum Value");
2460 result = (bool)atoi(exp.constant);
2462 else if(wh.type && (wh.type.kind == charType || (wh.type.kind == classType && wh.type._class &&
2463 wh.type._class.registered && !strcmp(wh.type._class.registered.fullName, "ecere::com::unichar"))) )
2470 if(exp.constant[0] == '\'')
2472 if((int)((byte *)exp.constant)[1] > 127)
2475 value = UTF8GetChar(exp.constant + 1, &nb);
2476 if(nb < 2) value = exp.constant[1];
2477 signedValue = value;
2481 signedValue = exp.constant[1];
2483 // Precomp Syntax error with boot strap here:
2484 byte b = (byte)(char)signedValue;
2485 value = (unichar) b;
2491 if(wh.type.kind == charType && wh.type.isSigned)
2493 signedValue = (int)(char)strtol(exp.constant, null, 0);
2495 // Precomp Syntax error with boot strap here:
2496 byte b = (byte)(char)signedValue;
2497 value = (unichar) b;
2502 value = (uint)strtoul(exp.constant, null, 0);
2503 signedValue = (int)value;
2507 UTF32toUTF8Len(&value, 1, charString, 5);
2509 snprintf(string, sizeof(string), "\'\\0' (0)");
2510 else if(value == '\t')
2511 snprintf(string, sizeof(string), "\'\\t' (%d)", value);
2512 else if(value == '\n')
2513 snprintf(string, sizeof(string), "\'\\n' (%d)", value);
2514 else if(value == '\r')
2515 snprintf(string, sizeof(string), "\'\\r' (%d)", value);
2516 else if(wh.type.kind == charType && wh.type.isSigned)
2517 snprintf(string, sizeof(string), "\'%s\' (%d)", charString, signedValue);
2518 else if(value > 256 || wh.type.kind != charType)
2520 if(value > 0x10FFFF || !GetCharCategory(value))
2521 snprintf(string, sizeof(string), $"Invalid Unicode Keypoint (0x%08X)", value);
2523 snprintf(string, sizeof(string), "\'%s\' (U+%04X)", charString, value);
2526 snprintf(string, sizeof(string), "\'%s\' (%d)", charString, value);
2527 string[sizeof(string)-1] = 0;
2529 wh.value = CopyString(string);
2534 wh.value = CopyString(exp.constant);
2535 result = (bool)atoi(exp.constant);
2541 wh.value = PrintHexUInt64(exp.address);
2542 result = (bool)exp.address;
2546 char tempString[256];
2547 if(exp.member.memberType == propertyMember)
2548 snprintf(watchmsg, sizeof(watchmsg), $"Missing property evaluation support for \"%s\"", wh.expression);
2550 snprintf(watchmsg, sizeof(watchmsg), $"Evaluation failed for \"%s\" of type \"%s\"", wh.expression,
2551 exp.type.OnGetString(tempString, null, null));
2557 snprintf(watchmsg, sizeof(watchmsg), $"Invalid expression: \"%s\"", wh.expression);
2558 if(exp) FreeExpression(exp);
2561 SetPrivateModule(backupPrivateModule);
2562 SetCurrentContext(backupContext);
2563 SetTopContext(backupContext);
2564 SetGlobalContext(backupContext);
2565 SetThisClass(backupThisClass);
2568 // wh.value = CopyString("No source file found for selected frame");
2570 watchmsg[sizeof(watchmsg)-1] = 0;
2572 wh.value = CopyString(watchmsg);
2574 ide.watchesView.UpdateWatch(wh);
2578 void EvaluateWatches()
2580 for(wh : ide.workspace.watches)
2584 char * ::GdbEvaluateExpression(char * expression)
2588 GdbCommand(false, "-data-evaluate-expression \"%s\"", expression);
2590 ide.outputView.debugBox.Logf("Debugger Error: GdbEvaluateExpression\n");
2594 // to be removed... use GdbReadMemory that returns a byte array instead
2595 char * ::GdbReadMemoryString(uint64 address, int size, char format, int rows, int cols)
2601 printf("GdbReadMemoryString called with size = 0!\n");
2603 // GdbCommand(false, "-data-read-memory 0x%08x %c, %d, %d, %d", address, format, size, rows, cols);
2604 if(GetRuntimePlatform() == win32)
2605 GdbCommand(false, "-data-read-memory 0x%016I64x %c, %d, %d, %d", address, format, size, rows, cols);
2607 GdbCommand(false, "-data-read-memory 0x%016llx %c, %d, %d, %d", address, format, size, rows, cols);
2609 ide.outputView.debugBox.Logf("Debugger Error: GdbReadMemoryString\n");
2613 byte * ::GdbReadMemory(uint64 address, int bytes)
2617 //GdbCommand(false, "-data-read-memory 0x%08x %c, 1, 1, %d", address, 'u', bytes);
2618 if(GetRuntimePlatform() == win32)
2619 GdbCommand(false, "-data-read-memory 0x%016I64x %c, 1, 1, %d", address, 'u', bytes);
2621 GdbCommand(false, "-data-read-memory 0x%016llx %c, 1, 1, %d", address, 'u', bytes);
2624 printf("GdbReadMemory called with bytes = 0!\n");
2627 ide.outputView.debugBox.Logf("Debugger Error: GdbReadMemory\n");
2628 else if(eval.result && strcmp(eval.result, "N/A"))
2630 byte * result = new byte[bytes];
2631 byte * string = eval.result;
2635 result[c++] = (byte)strtol(string, &string, 10);
2651 void EventHit(GdbDataStop stopItem)
2653 bool conditionMet = true;
2654 Breakpoint bp = bpHit;
2656 if(!bp && bpRunToCursor)
2660 GdbCommand(false, "-break-delete %d", bp.bp.number);
2665 if(bp.type == user && stopItem.frame.line && bp.line != stopItem.frame.line)
2667 bp.line = stopItem.frame.line;
2668 ide.breakpointsView.UpdateBreakpoint(bp.row);
2669 ide.workspace.Save();
2675 case internalWinMain:
2676 GdbBreakpointsInsert();
2677 if(userBreakOnInternBreak)
2679 userBreakOnInternBreak = false;
2680 // Why was SelectFrame missing here?
2681 SelectFrame(activeFrameLevel);
2682 GoToStackFrameLine(activeFrameLevel, true);
2683 ideMainFrame.Activate(); // TOFIX: ide.Activate() is not reliable (app inactive)
2687 GdbExecContinue(false);
2689 case internalModulesLoaded:
2691 GdbInsertInternalBreakpoints();
2692 GdbBreakpointsInsert();
2693 GdbExecContinue(false);
2695 case internalModuleLoad:
2696 GdbBreakpointsInsert();
2697 GdbExecContinue(false);
2702 conditionMet = ResolveWatch(bp.condition);
2704 if((bp.level == -1 || bp.level == frameCount-1) && conditionMet)
2709 ignoreBreakpoints = false;
2710 // Why was SelectFrame missing here?
2711 SelectFrame(activeFrameLevel);
2712 GoToStackFrameLine(activeFrameLevel, true);
2713 ideMainFrame.Activate(); // TOFIX: ide.Activate() is not reliable (app inactive)
2715 if(bp.type == BreakpointType::runToCursor)
2717 delete bpRunToCursor;
2718 bpRunToCursor = null;
2724 GdbExecContinue(false);
2728 GdbExecContinue(false);
2729 ide.breakpointsView.UpdateBreakpoint(bp.row);
2734 ide.outputView.debugBox.Logf("Debugger Error: Breakpoint hit could not match breakpoint instance\n");
2737 void GdbThreadExit()
2739 if(state != terminated)
2741 ChangeState(terminated);
2742 targetProcessId = 0;
2743 ClearBreakDisplay();
2747 serialSemaphore.Release();
2752 ide.outputView.debugBox.Logf($"Debugger Fatal Error: GDB lost\n");
2753 ide.outputView.debugBox.Logf($"Debugging stopped\n");
2756 //ChangeState(terminated);
2760 void GdbThreadMain(char * output)
2763 Array<char *> outTokens { minAllocSize = 50 };
2764 Array<char *> subTokens { minAllocSize = 50 };
2765 DebugListItem item { };
2766 DebugListItem item2 { };
2767 bool setWaitingForPID = false;
2769 #if defined(GDB_DEBUG_CONSOLE) || defined(GDB_DEBUG_GUI)
2770 #ifdef GDB_DEBUG_CONSOLE
2771 Log(output); Log("\n");
2773 #ifdef GDB_DEBUG_OUTPUT
2775 int len = strlen(output);
2783 for(c = 0; c < len / 1024; c++)
2785 strncpy(tmp, start, 1024);
2786 ide.outputView.gdbBox.Logf("out: %s\n", tmp);
2789 ide.outputView.gdbBox.Logf("out: %s\n", start);
2793 ide.outputView.gdbBox.Logf("out: %s\n", output);
2797 #ifdef GDB_DEBUG_CONSOLE
2798 strcpy(lastGdbOutput, output);
2800 #ifdef GDB_DEBUG_GUI
2801 if(ide.gdbDialog) ide.gdbDialog.AddOutput(output);
2808 if(strstr(output, "No debugging symbols found") || strstr(output, "(no debugging symbols found)"))
2811 ide.outputView.debugBox.Logf($"Target doesn't contain debug information!\n");
2817 if(TokenizeList(output, ',', outTokens) && !strcmp(outTokens[0], "^done"))
2819 //if(outTokens.count == 1)
2824 ChangeState(loaded);
2825 targetProcessId = 0;
2826 if(outTokens.count > 1 && TokenizeListItem(outTokens[1], item))
2828 if(!strcmp(item.name, "reason"))
2830 char * reason = item.value;
2831 StripQuotes(reason, reason);
2832 if(!strcmp(reason, "exited-normally") || !strcmp(reason, "exited") || !strcmp(reason, "exited-signalled"))
2835 if(outTokens.count > 2 && TokenizeListItem(outTokens[2], item2))
2837 StripQuotes(item2.value, item2.value);
2838 if(!strcmp(item2.name, "exit-code"))
2839 exitCode = item2.value;
2845 HandleExit(reason, exitCode);
2849 DebuggerProtocolUnknown("Unknown kill reply", item.name);
2852 HandleExit(null, null);
2855 if(outTokens.count > 1 && TokenizeListItem(outTokens[1], item))
2857 if(!strcmp(item.name, "bkpt"))
2859 sentBreakInsert = false;
2862 printf("problem\n");
2864 bpItem = GdbDataBreakpoint { };
2865 item.value = StripCurlies(item.value);
2866 TokenizeList(item.value, ',', subTokens);
2867 for(i = 0; i < subTokens.count; i++)
2869 if(TokenizeListItem(subTokens[i], item))
2871 StripQuotes(item.value, item.value);
2872 if(!strcmp(item.name, "number"))
2873 bpItem.number = atoi(item.value);
2874 else if(!strcmp(item.name, "type"))
2875 bpItem.type = CopyString(item.value);
2876 else if(!strcmp(item.name, "disp"))
2877 bpItem.disp = CopyString(item.value);
2878 else if(!strcmp(item.name, "enabled"))
2879 bpItem.enabled = (!strcmpi(item.value, "y"));
2880 else if(!strcmp(item.name, "addr"))
2881 bpItem.addr = CopyString(item.value);
2882 else if(!strcmp(item.name, "func"))
2883 bpItem.func = CopyString(item.value);
2884 else if(!strcmp(item.name, "file"))
2885 bpItem.file = item.value;
2886 else if(!strcmp(item.name, "line"))
2887 bpItem.line = atoi(item.value);
2888 else if(!strcmp(item.name, "at"))
2889 bpItem.at = CopyString(item.value);
2890 else if(!strcmp(item.name, "times"))
2891 bpItem.times = atoi(item.value);
2894 //breakType = bpValidation;
2895 //app.SignalEvent();
2896 subTokens.RemoveAll();
2898 else if(!strcmp(item.name, "BreakpointTable"))
2899 ide.outputView.debugBox.Logf("Debugger Error: Command reply BreakpointTable not handled\n");
2900 else if(!strcmp(item.name, "depth"))
2902 StripQuotes(item.value, item.value);
2903 frameCount = atoi(item.value);
2905 stackFrames.Free(Frame::Free);
2907 else if(!strcmp(item.name, "stack"))
2910 if(stackFrames.count)
2911 ide.callStackView.Logf("...\n");
2914 item.value = StripBrackets(item.value);
2915 TokenizeList(item.value, ',', subTokens);
2916 for(i = 0; i < subTokens.count; i++)
2918 if(TokenizeListItem(subTokens[i], item))
2920 if(!strcmp(item.name, "frame"))
2923 stackFrames.Add(frame);
2924 item.value = StripCurlies(item.value);
2925 ParseFrame(frame, item.value);
2926 if(frame.file && frame.from)
2927 DebuggerProtocolUnknown("Unexpected frame file and from members present", "");
2931 if(activeFrameLevel == -1)
2933 if(ide.projectView.IsModuleInProject(frame.file));
2935 if(frame.level != 0)
2937 //stopItem.frame = frame;
2938 breakType = selectFrame;
2941 activeFrame = frame;
2942 activeFrameLevel = frame.level;
2945 ide.callStackView.Logf("%3d ", frame.level);
2946 if(!strncmp(frame.func, "__ecereMethod_", strlen("__ecereMethod_")))
2947 ide.callStackView.Logf($"%s Method, %s:%d\n", &frame.func[strlen("__ecereMethod_")], (s = CopySystemPath(frame.file)), frame.line);
2948 else if(!strncmp(frame.func, "__ecereProp_", strlen("__ecereProp_")))
2949 ide.callStackView.Logf($"%s Property, %s:%d\n", &frame.func[strlen("__ecereProp_")], (s = CopySystemPath(frame.file)), frame.line);
2950 else if(!strncmp(frame.func, "__ecereConstructor_", strlen("__ecereConstructor_")))
2951 ide.callStackView.Logf($"%s Constructor, %s:%d\n", &frame.func[strlen("__ecereConstructor_")], (s = CopySystemPath(frame.file)), frame.line);
2952 else if(!strncmp(frame.func, "__ecereDestructor_", strlen("__ecereDestructor_")))
2953 ide.callStackView.Logf($"%s Destructor, %s:%d\n", &frame.func[strlen("__ecereDestructor_")], (s = CopySystemPath(frame.file)), frame.line);
2955 ide.callStackView.Logf($"%s Function, %s:%d\n", frame.func, (s = CopySystemPath(frame.file)), frame.line);
2960 ide.callStackView.Logf("%3d ", frame.level);
2965 ide.callStackView.Logf($"inside %s, %s\n", frame.func, (s = CopySystemPath(frame.from)));
2969 ide.callStackView.Logf("%s\n", frame.func);
2971 ide.callStackView.Logf($"unknown source\n");
2975 DebuggerProtocolUnknown("Unknown stack content", item.name);
2978 if(activeFrameLevel == -1)
2980 activeFrameLevel = 0;
2981 activeFrame = stackFrames.first;
2983 ide.callStackView.Home();
2985 subTokens.RemoveAll();
2987 /*else if(!strcmp(item.name, "frame"))
2990 item.value = StripCurlies(item.value);
2991 ParseFrame(&frame, item.value);
2993 else if(!strcmp(item.name, "thread-ids"))
2995 ide.threadsView.Clear();
2996 item.value = StripCurlies(item.value);
2997 TokenizeList(item.value, ',', subTokens);
2998 for(i = subTokens.count - 1; ; i--)
3000 if(TokenizeListItem(subTokens[i], item))
3002 if(!strcmp(item.name, "thread-id"))
3005 StripQuotes(item.value, item.value);
3006 value = atoi(item.value);
3007 ide.threadsView.Logf("%3d \n", value);
3010 DebuggerProtocolUnknown("Unknown threads content", item.name);
3015 ide.threadsView.Home();
3017 subTokens.RemoveAll();
3018 //if(!strcmp(outTokens[2], "number-of-threads"))
3020 else if(!strcmp(item.name, "new-thread-id"))
3022 StripQuotes(item.value, item.value);
3023 activeThread = atoi(item.value);
3025 else if(!strcmp(item.name, "value"))
3027 StripQuotes(item.value, item.value);
3028 eval.result = CopyString(item.value);
3029 eval.active = false;
3031 else if(!strcmp(item.name, "addr"))
3033 for(i = 2; i < outTokens.count; i++)
3035 if(TokenizeListItem(outTokens[i], item))
3037 if(!strcmp(item.name, "total-bytes"))
3039 StripQuotes(item.value, item.value);
3040 eval.bytes = atoi(item.value);
3042 else if(!strcmp(item.name, "next-row"))
3044 StripQuotes(item.value, item.value);
3045 eval.nextBlockAddress = _strtoui64(item.value, null, 0);
3047 else if(!strcmp(item.name, "memory"))
3051 //StripQuotes(item.value, item.value);
3052 item.value = StripBrackets(item.value);
3053 // this should be treated as a list...
3054 item.value = StripCurlies(item.value);
3055 TokenizeList(item.value, ',', subTokens);
3056 for(j = 0; j < subTokens.count; j++)
3058 if(TokenizeListItem(subTokens[j], item))
3060 if(!strcmp(item.name, "data"))
3062 item.value = StripBrackets(item.value);
3063 StripQuotes2(item.value, item.value);
3064 eval.result = CopyString(item.value);
3065 eval.active = false;
3069 subTokens.RemoveAll();
3074 else if(!strcmp(item.name, "source-path"))
3078 DebuggerProtocolUnknown("Unknown command reply", item.name);
3081 else if(!strcmp(outTokens[0], "^running"))
3083 waitingForPID = true;
3084 setWaitingForPID = true;
3086 else if(!strcmp(outTokens[0], "^exit"))
3088 ChangeState(terminated);
3089 // ide.outputView.debugBox.Logf("Exit\n");
3090 // ide.Update(null);
3092 serialSemaphore.Release();
3094 else if(!strcmp(outTokens[0], "^error"))
3098 sentBreakInsert = false;
3099 breakpointError = true;
3102 printf("problem\n");
3104 bpItem = GdbDataBreakpoint { };
3107 if(outTokens.count > 1 && TokenizeListItem(outTokens[1], item))
3109 if(!strcmp(item.name, "msg"))
3111 StripQuotes(item.value, item.value);
3114 eval.active = false;
3116 if(strstr(item.value, "No symbol") && strstr(item.value, "in current context"))
3117 eval.error = symbolNotFound;
3118 else if(strstr(item.value, "Cannot access memory at address"))
3119 eval.error = memoryCantBeRead;
3121 eval.error = unknown;
3123 else if(!strcmp(item.value, "Previous frame inner to this frame (corrupt stack?)"))
3126 else if(!strncmp(item.value, "Cannot access memory at address", 31))
3129 else if(!strcmp(item.value, "Cannot find bounds of current function"))
3131 ChangeState(stopped);
3132 gdbHandle.Printf("-exec-continue\n");
3134 else if(!strcmp(item.value, "ptrace: No such process."))
3136 ChangeState(loaded);
3137 targetProcessId = 0;
3139 else if(!strcmp(item.value, "Function \\\"WinMain\\\" not defined."))
3142 else if(!strcmp(item.value, "You can't do that without a process to debug."))
3144 ChangeState(loaded);
3145 targetProcessId = 0;
3147 else if(strstr(item.value, "No such file or directory."))
3149 ChangeState(loaded);
3150 targetProcessId = 0;
3152 else if(strstr(item.value, "During startup program exited with code "))
3154 ChangeState(loaded);
3155 targetProcessId = 0;
3160 if(strlen(item.value) < MAX_F_STRING)
3163 ide.outputView.debugBox.Logf("GDB: %s\n", (s = CopyUnescapedString(item.value)));
3167 ide.outputView.debugBox.Logf("GDB: %s\n", item.value);
3173 DebuggerProtocolUnknown("Unknown error content", item.name);
3176 DebuggerProtocolUnknown("Unknown result-record", outTokens[0]);
3178 outTokens.RemoveAll();
3181 DebuggerProtocolUnknown("Unknown status-async-output", outTokens[0]);
3184 if(TokenizeList(output, ',', outTokens) && !strcmp(outTokens[0], "=thread-group-created")) //=thread-group-created,id="7611"
3186 else if(!strcmp(outTokens[0], "=thread-created")) //=thread-created,id="1",group-id="7611"
3188 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"
3191 DebuggerProtocolUnknown("Unknown notify-async-output", outTokens[0]);
3192 outTokens.RemoveAll();
3196 if(TokenizeList(output, ',', outTokens))
3198 if(!strcmp(outTokens[0],"*running"))
3200 waitingForPID = true;
3201 setWaitingForPID = true;
3203 else if(!strcmp(outTokens[0], "*stopped"))
3206 ChangeState(stopped);
3208 for(tk = 1; tk < outTokens.count; tk++)
3210 if(TokenizeListItem(outTokens[tk], item))
3212 if(!strcmp(item.name, "reason"))
3214 char * reason = item.value;
3215 StripQuotes(reason, reason);
3216 if(!strcmp(reason, "exited-normally") || !strcmp(reason, "exited") || !strcmp(reason, "exited-signalled"))
3219 if(outTokens.count > tk+1 && TokenizeListItem(outTokens[tk+1], item2))
3222 StripQuotes(item2.value, item2.value);
3223 if(!strcmp(item2.name, "exit-code"))
3224 exitCode = item2.value;
3230 HandleExit(reason, exitCode);
3232 else if(!strcmp(reason, "breakpoint-hit"))
3236 printf("problem\n");
3238 stopItem = GdbDataStop { };
3240 for(i = tk+1; i < outTokens.count; i++)
3242 TokenizeListItem(outTokens[i], item);
3243 StripQuotes(item.value, item.value);
3244 if(!strcmp(item.name, "bkptno"))
3245 stopItem.bkptno = atoi(item.value);
3246 else if(!strcmp(item.name, "thread-id"))
3247 stopItem.threadid = atoi(item.value);
3248 else if(!strcmp(item.name, "frame"))
3250 item.value = StripCurlies(item.value);
3251 ParseFrame(stopItem.frame, item.value);
3254 DebuggerProtocolUnknown("Unknown breakpoint hit item name", item.name);
3259 else if(!strcmp(reason, "end-stepping-range"))
3263 printf("problem\n");
3265 stopItem = GdbDataStop { };
3267 for(i = tk+1; i < outTokens.count; i++)
3269 TokenizeListItem(outTokens[i], item);
3270 StripQuotes(item.value, item.value);
3271 if(!strcmp(item.name, "thread-id"))
3272 stopItem.threadid = atoi(item.value);
3273 else if(!strcmp(item.name, "frame"))
3275 item.value = StripCurlies(item.value);
3276 ParseFrame(stopItem.frame, item.value);
3278 else if(!strcmp(item.name, "reason"))
3280 else if(!strcmp(item.name, "bkptno"))
3283 DebuggerProtocolUnknown("Unknown end of stepping range item name", item.name);
3289 else if(!strcmp(reason, "function-finished"))
3293 printf("problem\n");
3295 stopItem = GdbDataStop { };
3296 stopItem.reason = CopyString(reason);
3298 for(i = tk+1; i < outTokens.count; i++)
3300 TokenizeListItem(outTokens[i], item);
3301 StripQuotes(item.value, item.value);
3302 if(!strcmp(item.name, "thread-id"))
3303 stopItem.threadid = atoi(item.value);
3304 else if(!strcmp(item.name, "frame"))
3306 item.value = StripCurlies(item.value);
3307 ParseFrame(stopItem.frame, item.value);
3309 else if(!strcmp(item.name, "gdb-result-var"))
3310 stopItem.gdbResultVar = CopyString(item.value);
3311 else if(!strcmp(item.name, "return-value"))
3312 stopItem.returnValue = CopyString(item.value);
3314 DebuggerProtocolUnknown("Unknown function finished item name", item.name);
3317 event = functionEnd;
3320 else if(!strcmp(reason, "signal-received"))
3324 printf("problem\n");
3326 stopItem = GdbDataStop { };
3327 stopItem.reason = CopyString(reason);
3329 for(i = tk+1; i < outTokens.count; i++)
3331 TokenizeListItem(outTokens[i], item);
3332 StripQuotes(item.value, item.value);
3333 if(!strcmp(item.name, "signal-name"))
3334 stopItem.name = CopyString(item.value);
3335 else if(!strcmp(item.name, "signal-meaning"))
3336 stopItem.meaning = CopyString(item.value);
3337 else if(!strcmp(item.name, "thread-id"))
3338 stopItem.threadid = atoi(item.value);
3339 else if(!strcmp(item.name, "frame"))
3341 item.value = StripCurlies(item.value);
3342 ParseFrame(stopItem.frame, item.value);
3345 DebuggerProtocolUnknown("Unknown signal reveived item name", item.name);
3347 if(!strcmp(stopItem.name, "SIGTRAP"))
3366 else if(!strcmp(reason, "watchpoint-trigger"))
3367 DebuggerProtocolUnknown("Reason watchpoint trigger not handled", "");
3368 else if(!strcmp(reason, "read-watchpoint-trigger"))
3369 DebuggerProtocolUnknown("Reason read watchpoint trigger not handled", "");
3370 else if(!strcmp(reason, "access-watchpoint-trigger"))
3371 DebuggerProtocolUnknown("Reason access watchpoint trigger not handled", "");
3372 else if(!strcmp(reason, "watchpoint-scope"))
3373 DebuggerProtocolUnknown("Reason watchpoint scope not handled", "");
3374 else if(!strcmp(reason, "location-reached"))
3375 DebuggerProtocolUnknown("Reason location reached not handled", "");
3377 DebuggerProtocolUnknown("Unknown reason", reason);
3385 DebuggerProtocolUnknown("Unknown exec-async-output", outTokens[0]);
3386 outTokens.RemoveAll();
3389 if(!strcmpi(output, "(gdb) "))
3393 char exeFile[MAX_LOCATION];
3394 int oldProcessID = targetProcessId;
3395 GetLastDirectory(targetFile, exeFile);
3399 targetProcessId = Process_GetChildExeProcessId(gdbProcessId, exeFile);
3400 if(targetProcessId || gdbHandle.Peek()) break;
3405 ChangeState(running);
3406 else if(!oldProcessID)
3408 ide.outputView.debugBox.Logf($"Debugger Error: No target process ID\n");
3409 // TO VERIFY: The rest of this block has not been thoroughly tested in this particular location
3410 gdbHandle.Printf("-gdb-exit\n");
3412 ChangeState(terminated); //loaded;
3417 for(bp : ide.workspace.breakpoints)
3418 bp.inserted = false;
3421 bp.inserted = false;
3423 bpRunToCursor.inserted = false;
3425 ide.outputView.debugBox.Logf($"Debugging stopped\n");
3426 ClearBreakDisplay();
3428 #if defined(__unix__)
3429 if(FileExists(progFifoPath)) //fileCreated)
3431 progThread.terminate = true;
3434 fifoFile.CloseInput();
3441 DeleteFile(progFifoPath);
3442 progFifoPath[0] = '\0';
3449 serialSemaphore.Release();
3452 DebuggerProtocolUnknown($"Unknown prompt", output);
3456 if(!strncmp(output, "&\"warning:", 10))
3459 content = strstr(output, "\"");
3460 StripQuotes(content, content);
3461 content = strstr(content, ":");
3467 ide.outputView.debugBox.LogRaw((s = CopyUnescapedString(content)));
3474 DebuggerProtocolUnknown($"Unknown output", output);
3476 if(!setWaitingForPID)
3477 waitingForPID = false;
3478 setWaitingForPID = false;
3486 void RunToCursorPrepare(char * absoluteFilePath, char * relativeFilePath, int lineNumber)
3490 //bpRunToCursor.Free();
3491 bpRunToCursor = Breakpoint { };
3494 bpRunToCursor = Breakpoint { };
3496 if(absoluteFilePath)
3497 bpRunToCursor.absoluteFilePath = CopyString(absoluteFilePath);
3498 if(relativeFilePath)
3499 bpRunToCursor.relativeFilePath = CopyString(relativeFilePath);
3500 bpRunToCursor.line = lineNumber;
3501 bpRunToCursor.type = runToCursor;
3502 bpRunToCursor.enabled = true;
3503 bpRunToCursor.condition = null;
3504 bpRunToCursor.ignore = 0;
3505 bpRunToCursor.level = -1;
3508 ExpressionType ::DebugEvalExpTypeError(char * result)
3514 case symbolNotFound:
3515 return symbolErrorExp;
3516 case memoryCantBeRead:
3517 return memoryErrorExp;
3519 return unknownErrorExp;
3522 char * ::EvaluateExpression(char * expression, ExpressionType * error)
3525 if(ide.projectView && ide.debugger.state == stopped)
3527 result = GdbEvaluateExpression(expression);
3528 *error = DebugEvalExpTypeError(result);
3533 *error = noDebuggerErrorExp;
3538 char * ::ReadMemory(uint64 address, int size, char format, ExpressionType * error)
3541 char * result = GdbReadMemoryString(address, size, format, 1, 1);
3542 if(!result || !strcmp(result, "N/A"))
3543 *error = memoryErrorExp;
3545 *error = DebugEvalExpTypeError(result);
3550 class GdbThread : Thread
3556 static char output[4096];
3557 Array<char> dynamicBuffer { minAllocSize = 4096 };
3558 DualPipe oldGdbHandle = gdbHandle;
3559 incref oldGdbHandle;
3562 while(debugger.state != terminated && gdbHandle && !gdbHandle.Eof())
3566 result = gdbHandle.Read(output, 1, sizeof(output));
3568 if(debugger.state == terminated || !gdbHandle || gdbHandle.Eof())
3575 for(c = 0; c<result; c++)
3577 if(output[c] == '\n')
3579 int pos = dynamicBuffer.size;
3580 dynamicBuffer.size += c - start;
3581 memcpy(&dynamicBuffer[pos], output + start, c - start);
3582 if(dynamicBuffer.count && dynamicBuffer[dynamicBuffer.count - 1] != '\r')
3583 // COMMENTED OUT DUE TO ISSUE #135, FIXED
3584 //if(dynamicBuffer.array[dynamicBuffer.count - 1] != '\r')
3585 dynamicBuffer.size++;
3586 dynamicBuffer[dynamicBuffer.count - 1] = '\0';
3588 // printf("%s\n", dynamicBuffer.array);
3590 debugger.GdbThreadMain(&dynamicBuffer[0]);
3591 dynamicBuffer.size = 0;
3597 int pos = dynamicBuffer.size;
3598 dynamicBuffer.size += c - start;
3599 memcpy(&dynamicBuffer[pos], output + start, c - start);
3605 printf("Got end of file from GDB!\n");
3609 delete dynamicBuffer;
3610 //if(oldGdbHandle == gdbHandle)
3611 debugger.GdbThreadExit();
3612 delete oldGdbHandle;
3618 static define createFIFOMsg = $"err: Unable to create FIFO %s\n";
3619 static define openFIFOMsg = $"err: Unable to open FIFO %s for read\n";
3621 #if defined(__unix__)
3626 #include <sys/types.h>
3631 class ProgramThread : Thread
3637 bool fileCreated = false;
3639 static char output[1000];
3642 /*if(!mkfifo(progFifoPath, mask))
3649 ide.outputView.debugBox.Logf($"err: Unable to create FIFO %s\n", progFifoPath);
3653 if(FileExists(progFifoPath)) //fileCreated)
3655 fifoFile = FileOpen(progFifoPath, read);
3659 ide.outputView.debugBox.Logf(openFIFOMsg, progFifoPath);
3664 fd = fileno((FILE *)fifoFile.input);
3665 //fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
3669 while(!terminate && fifoFile && !fifoFile.Eof())
3672 struct timeval time;
3680 selectResult = select(fd + 1, &rs, null, null, &time);
3681 if(FD_ISSET(fd, &rs))
3683 int result = (int)read(fd, output, sizeof(output)-1);
3684 if(!result || (result < 0 && errno != EAGAIN))
3688 output[result] = '\0';
3689 if(strcmp(output,"&\"warning: GDB: Failed to set controlling terminal: Invalid argument\\n\"\n"))
3692 ide.outputView.debugBox.Log(output);
3701 //fifoFile.CloseInput();
3704 ide.outputView.debugBox.Log("\n");
3708 if(FileExists(progFifoPath)) //fileCreated)
3710 DeleteFile(progFifoPath);
3711 progFifoPath[0] = '\0';
3719 class Argument : struct
3721 Argument prev, next;
3737 class Frame : struct
3746 property char * from { set { delete from; if(value) from = CopyUnescapedUnixPath(value); } }
3748 property char * file { set { delete file; if(value) file = CopyUnescapedUnixPath(value); } }
3749 char * absoluteFile;
3758 delete absoluteFile;
3759 args.Free(Argument::Free);
3768 class GdbDataStop : struct
3785 char * gdbResultVar;
3795 if(!strcmp(reason, "signal-received"))
3800 else if(!strcmp(reason, "function-finished"))
3802 delete gdbResultVar;
3807 if(frame) frame.Free();
3816 class GdbDataBreakpoint : struct
3825 property char * file { set { delete file; if(value) file = CopyUnescapedUnixPath(value); } }
3840 ~GdbDataBreakpoint()
3846 class Breakpoint : struct
3850 char * relativeFilePath;
3851 char * absoluteFilePath;
3860 BreakpointType type;
3863 GdbDataBreakpoint bp;
3865 char * LocationToString()
3867 char location[MAX_LOCATION+20];
3868 snprintf(location, sizeof(location), "%s:%d", relativeFilePath, line);
3869 location[sizeof(location)-1] = 0;
3870 #if defined(__WIN32__)
3871 ChangeCh(location, '/', '\\');
3873 return CopyString(location);
3878 if(relativeFilePath && relativeFilePath[0])
3880 f.Printf(" * %d,%d,%d,%d,%s\n", enabled ? 1 : 0, ignore, level, line, relativeFilePath);
3882 f.Printf(" ~ %s\n", condition.expression);
3891 delete relativeFilePath;
3892 delete absoluteFilePath;
3902 class Watch : struct
3913 f.Printf(" ~ %s\n", expression);
3937 class DebugListItem : struct
3943 struct DebugEvaluationData
3948 uint64 nextBlockAddress;
3950 DebuggerEvaluationError error;
3953 class CodeLocation : struct
3956 char * absoluteFile;
3959 CodeLocation ::ParseCodeLocation(char * location)
3963 char * colon = null;
3965 char loc[MAX_LOCATION];
3966 strcpy(loc, location);
3967 for(temp = loc; temp = strstr(temp, ":"); temp++)
3975 int line = atoi(colon);
3978 CodeLocation codloc { line = line };
3979 codloc.file = CopyString(loc);
3980 codloc.absoluteFile = ide.workspace.GetAbsolutePathFromRelative(loc);
3992 delete absoluteFile;