6 //#define GDB_DEBUG_CONSOLE
8 extern char * strrchr(char * s, char c);
20 #include <sys/time.h> // Required on Apple...
24 //bool eString_PathInsidePath(char * to, char * path)
25 bool eString_PathInsideOf(char * path, char * of)
27 if(!path[0] || !of[0])
28 return false; // What to do here? Ever used?
31 char ofPart[MAX_FILENAME], ofRest[MAX_LOCATION];
32 char pathPart[MAX_FILENAME], pathRest[MAX_LOCATION];
34 strcpy(pathRest, path);
35 for(; ofRest[0] && pathRest[0];)
37 SplitDirectory(ofRest, ofPart, ofRest);
38 SplitDirectory(pathRest, pathPart, pathRest);
39 if(fstrcmp(pathPart, ofPart))
42 if(!ofRest[0] && !pathRest[0]) // paths are identical - should return false or true? (changed to false)
44 else if(!pathRest[0]) // not inside of, it's the other way around
50 public char * StripQuotes2(char * string, char * output)
54 bool quoted = false, escaped = false;
56 for(c = 0; ch = string[c]; c++)
60 if(escaped || ch != '\"')
79 static void strescpy(char * d, char * s)
132 static char * CopyUnescapedSystemPath(char * p)
134 char * d = new char[strlen(p) + 1];
136 #if defined(__WIN32__)
137 ChangeCh(d, '/', '\\');
142 static char * CopyUnescapedUnixPath(char * p)
144 char * d = new char[strlen(p) + 1];
146 #if defined(__WIN32__)
147 ChangeCh(d, '\\', '/');
152 static char * CopyUnescapedString(char * s)
154 char * d = new char[strlen(s) + 1];
159 // String Unescape Copy
161 // TOFIX: THIS DOESN'T HANDLE NUMERIC ESCAPE CODES (OCTAL/HEXADECIMAL...)?
162 // Seems very similar to ReadString in pass15.ec (which also misses numeric escape codes :) )
164 static void struscpy(char * d, char * s)
216 static char * StripBrackets(char * string)
218 int length = strlen(string);
219 if(length > 1 && *string == '[' && string[length - 1] == ']')
222 string[length - 1] = '\0';
229 static char * StripCurlies(char * string)
231 int length = strlen(string);
232 if(length > 1 && *string == '{' && string[length - 1] == '}')
235 string[length - 1] = '\0';
242 static int StringGetInt(char * string, int start)
245 int i, len = strlen(string);
247 for(i = start; i < len && i < start + 8; i++)
249 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')
250 strncat(number, &string[i], 1);
257 static int TokenizeList(char * string, const char seperator, Array<char *> tokens)
261 bool quoted = false; //bool escaped = false;
262 char * start = string;
264 for(; *string; string++)
273 else if(*string == '\"')
275 else if(*string == '{' || *string == '[' || *string == '(' || *string == '<')
277 else if(*string == '}' || *string == ']' || *string == ')' || *string == '>')
279 else if(*string == seperator && !level)
288 //tokens[count] = start;
289 //tokens[count++] = start;
296 static bool TokenizeListItem(char * string, DebugListItem item)
298 char * equal = strstr(string, "=");
312 static void DebuggerProtocolUnknown(char * message, char * gdbOutput)
314 #ifdef _DEBUG_GDB_PROTOCOL
315 ide.outputView.debugBox.Logf("Debugger Protocol Error: %s (%s)\n", message, gdbOutput);
319 // define GdbGetLineSize = 1638400;
320 define GdbGetLineSize = 5638400;
321 #if defined(__unix__)
322 char progFifoPath[MAX_LOCATION];
323 char progFifoDir[MAX_LOCATION];
326 enum DebuggerState { none, prompt, loaded, running, stopped, terminated };
327 enum DebuggerEvent { none, hit, breakEvent, signal, stepEnd, functionEnd, exit };
328 enum DebuggerAction { none, internal, restart, stop, selectFrame }; //, bpValidation
329 enum BreakpointType { none, internalMain, internalWinMain, internalModulesLoaded, user, runToCursor };
330 enum DebuggerEvaluationError { none, symbolNotFound, memoryCantBeRead, unknown };
332 FileDialog debuggerFileDialog { type = selectDir };
334 static DualPipe gdbHandle;
335 static DebugEvaluationData eval { };
337 static int targetProcessId;
339 static bool gdbReady;
343 Semaphore serialSemaphore { };
348 //bool breakpointsInserted;
350 bool sentBreakInsert;
351 bool ignoreBreakpoints;
352 bool userBreakOnInternBreak;
359 int activeFrameLevel;
370 DebuggerAction breakType;
371 //DebuggerCommand lastCommand; // THE COMPILER COMPILES STUFF THAT DOES NOT EXIST???
373 GdbDataStop stopItem;
374 GdbDataBreakpoint bpItem;
377 List<Breakpoint> sysBPs { };
378 Breakpoint bpRunToCursor;
384 CompilerConfig currentCompiler;
385 ProjectConfig prjConfig;
387 CodeEditor codeEditor;
389 GdbThread gdbThread { debugger = this };
392 delay = 0.0, userData = this;
396 bool monitor = false;
397 DebuggerEvent curEvent = event;
398 GdbDataStop stopItem = this.stopItem;
404 this.stopItem = null;
407 if(curEvent && curEvent != exit)
410 printf("No stop item\n");
419 Restart(currentCompiler, prjConfig);
428 GdbCommand(false, "-stack-select-frame %d", activeFrameLevel);
429 for(activeFrame = stackFrames.first; activeFrame; activeFrame = activeFrame.next)
430 if(activeFrame.level == activeFrameLevel)
436 // GdbCommand(false, "-break-info %d", bpItem.number);
446 activeThread = stopItem.threadid;
447 GdbCommand(false, "-thread-list-ids");
452 Breakpoint bp = null;
454 for(i : ide.workspace.breakpoints; i.bp && i.bp.number == stopItem.bkptno)
461 for(i : sysBPs; i.bp && i.bp.number == stopItem.bkptno)
467 if(bp && bp.type != user && stopItem && stopItem.frame)
469 // In case the user put a breakpoint where an internal breakpoint is, avoid the confusion...
470 for(i : ide.workspace.breakpoints)
472 if(i.bp && i.line == stopItem.frame.line && !fstrcmp(i.absoluteFilePath, stopItem.frame.absoluteFile))
479 if(!(!userBreakOnInternBreak &&
480 bp && (bp.type == internalMain || bp.type == internalWinMain || bp.type == internalModulesLoaded)))
482 hitThread = stopItem.threadid;
486 signalThread = stopItem.threadid;
498 activeThread = stopItem.threadid;
499 GdbCommand(false, "-thread-list-ids");
501 if(activeFrameLevel > 0)
502 GdbCommand(false, "-stack-select-frame %d", activeFrameLevel);
504 WatchesCodeEditorLinkInit();
514 ide.outputView.debugBox.Logf($"Signal received: %s - %s\n", stopItem.name, stopItem.meaning);
515 ide.outputView.debugBox.Logf(" %s:%d\n", (s = CopySystemPath(stopItem.frame.file)), stopItem.frame.line);
521 // Why was SelectFrame missing here?
522 SelectFrame(activeFrameLevel);
523 GoToStackFrameLine(activeFrameLevel, curEvent == signal || curEvent == stepEnd /*false*/);
526 if(curEvent == signal)
527 ide.outputView.Show();
528 if(curEvent == signal || curEvent == breakEvent)
530 if(curEvent == breakEvent)
531 ide.threadsView.Show();
532 ide.callStackView.Show();
534 ide.ShowCodeEditor();
535 if(curEvent == breakEvent)
536 ide.callStackView.Activate();
544 ignoreBreakpoints = false;
555 #ifdef GDB_DEBUG_CONSOLE
556 char lastGdbOutput[GdbGetLineSize];
558 #if defined(__unix__)
559 ProgramThread progThread { };
562 void ChangeState(DebuggerState value)
564 bool same = value == state;
565 // if(same) PrintLn("Debugger::ChangeState -- changing to same state");
567 if(!same && ide) ide.AdjustDebugMenus();
572 // Stop(); // Don't need to call Stop here, because ~ProjectView() will call it explicitly.
574 stackFrames.Free(Frame::Free);
584 waitingForPID = false;
589 sentBreakInsert = false;
590 ignoreBreakpoints = false;
591 userBreakOnInternBreak = false;
594 activeFrameLevel = 0;
611 bpRunToCursor = null;
614 delete currentCompiler;
618 /*GdbThread gdbThread
624 ideProcessId = Process_GetCurrentProcessId();
626 sysBPs.Add(Breakpoint { type = internalMain, enabled = true, level = -1 });
627 #if defined(__WIN32__)
628 sysBPs.Add(Breakpoint { type = internalWinMain, enabled = true, level = -1 });
630 sysBPs.Add(Breakpoint { type = internalModulesLoaded, enabled = true, level = -1 });
643 property bool isActive { get { return state == running || state == stopped; } }
644 property bool isPrepared { get { return state == loaded || state == running || state == stopped; } }
648 GdbExecContinue(true);
656 GdbDebugBreak(false);
668 GdbDebugBreak(false);
679 void Restart(CompilerConfig compiler, ProjectConfig config)
687 GdbDebugBreak(false);
694 if(!GdbInit(compiler, config))
702 bool GoToCodeLine(char * location)
705 codloc = CodeLocation::ParseCodeLocation(location);
708 CodeEditor editor = (CodeEditor)ide.OpenFile(codloc.absoluteFile, normal, true, null, no, normal);
711 EditBox editBox = editor.editBox;
712 editBox.GoToLineNum(codloc.line - 1);
713 editBox.GoToPosition(editBox.line, codloc.line - 1, 0);
720 bool GoToStackFrameLine(int stackLevel, bool askForLocation)
724 char filePath[MAX_LOCATION];
725 char sourceDir[MAX_LOCATION];
727 CodeEditor editor = null;
728 if(stackLevel == -1) // this (the two lines) is part of that fix that I would not put in for some time
730 for(frame = stackFrames.first; frame; frame = frame.next)
731 if(frame.level == stackLevel)
735 ide.callStackView.Show();
737 if(!frame.absoluteFile && frame.file)
738 frame.absoluteFile = ide.workspace.GetAbsolutePathFromRelative(frame.file);
739 if(!frame.absoluteFile && askForLocation && frame.file)
742 char title[MAX_LOCATION];
744 sprintf(title, $"Provide source file location for %s", (s = CopySystemPath(frame.file)));
746 if(SourceDirDialog(title, ide.workspace.projectDir, frame.file, sourceDir))
748 AddSourceDir(sourceDir);
749 frame.absoluteFile = ide.workspace.GetAbsolutePathFromRelative(frame.file);
752 if(frame.absoluteFile)
753 editor = (CodeEditor)ide.OpenFile(frame.absoluteFile, normal, true, null, no, normal);
755 if(editor && frame.line)
757 EditBox editBox = editor.editBox;
758 editBox.GoToLineNum(frame.line - 1);
759 editBox.GoToPosition(editBox.line, frame.line - 1, 0);
767 void SelectThread(int thread)
771 if(thread != activeThread)
773 activeFrameLevel = -1;
774 ide.callStackView.Clear();
775 GdbCommand(false, "-thread-select %d", thread);
777 // Why was SelectFrame missing here?
778 SelectFrame(activeFrameLevel);
779 GoToStackFrameLine(activeFrameLevel, true);
780 WatchesCodeEditorLinkRelease();
781 WatchesCodeEditorLinkInit();
785 ide.callStackView.Show();
789 void SelectFrame(int frame)
793 if(frame != activeFrameLevel || !codeEditor || !codeEditor.visible)
795 activeFrameLevel = frame; // there is no active frame number in the gdb reply
796 GdbCommand(false, "-stack-select-frame %d", activeFrameLevel);
797 for(activeFrame = stackFrames.first; activeFrame; activeFrame = activeFrame.next)
798 if(activeFrame.level == activeFrameLevel)
801 WatchesCodeEditorLinkRelease();
802 WatchesCodeEditorLinkInit();
809 void HandleExit(char * reason, char * code)
811 bool returnedExitCode = false;
812 char verboseExitCode[128];
814 ChangeState(loaded); // this state change seems to be superfluous, might be in case of gdb crash
818 sprintf(verboseExitCode, $" with exit code %s", code);
820 verboseExitCode[0] = '\0';
824 // ClearBreakDisplay();
828 for(wh : ide.workspace.watches)
830 if(wh.type) FreeType(wh.type);
833 ide.watchesView.UpdateWatch(wh);
837 #if defined(__unix__)
838 progThread.terminate = true;
841 fifoFile.CloseInput();
850 char program[MAX_LOCATION];
851 GetSystemPathBuffer(program, targetFile);
853 ide.outputView.debugBox.Logf($"The program %s has exited%s.\n", program, verboseExitCode);
854 else if(!strcmp(reason, "exited-normally"))
855 ide.outputView.debugBox.Logf($"The program %s has exited normally%s.\n", program, verboseExitCode);
856 else if(!strcmp(reason, "exited"))
857 ide.outputView.debugBox.Logf($"The program %s has exited%s.\n", program, verboseExitCode);
858 else if(!strcmp(reason, "exited-signalled"))
859 ide.outputView.debugBox.Logf($"The program %s has exited with a signal%s.\n", program, verboseExitCode);
861 ide.outputView.debugBox.Logf($"The program %s has exited (gdb provided an unknown reason)%s.\n", program, verboseExitCode);
866 void Start(CompilerConfig compiler, ProjectConfig config)
868 ide.outputView.debugBox.Clear();
873 if(!GdbInit(compiler, config))
881 void StepInto(CompilerConfig compiler, ProjectConfig config)
887 if(!GdbInit(compiler, config))
890 ide.outputView.ShowClearSelectTab(debug);
891 ide.outputView.debugBox.Logf($"Starting debug mode\n");
892 userBreakOnInternBreak = true;
901 void StepOver(CompilerConfig compiler, ProjectConfig config, bool ignoreBkpts)
907 if(!GdbInit(compiler, config))
910 ide.outputView.ShowClearSelectTab(debug);
911 ide.outputView.debugBox.Logf($"Starting debug mode\n");
912 ignoreBreakpoints = ignoreBkpts;
913 userBreakOnInternBreak = true;
917 ignoreBreakpoints = ignoreBkpts;
918 if(ignoreBreakpoints)
919 GdbBreakpointsDelete(true);
925 void StepOut(bool ignoreBkpts)
929 ignoreBreakpoints = ignoreBkpts;
930 if(ignoreBreakpoints)
931 GdbBreakpointsDelete(true);
936 void RunToCursor(CompilerConfig compiler, ProjectConfig config, char * absoluteFilePath, int lineNumber, bool ignoreBkpts)
938 char relativeFilePath[MAX_LOCATION];
939 DebuggerState oldState = state;
940 ignoreBreakpoints = ignoreBkpts;
941 if(!ide.projectView.GetRelativePath(absoluteFilePath, relativeFilePath))
942 strcpy(relativeFilePath, absoluteFilePath);
947 Start(compiler, config);
954 ide.outputView.ShowClearSelectTab(debug);
955 ide.outputView.debugBox.Logf($"Starting debug mode\n");
957 RunToCursorPrepare(absoluteFilePath, relativeFilePath, lineNumber);
958 sentBreakInsert = true;
959 GdbCommand(false, "-break-insert %s:%d", relativeFilePath, lineNumber);
960 bpRunToCursor.bp = bpItem;
962 bpRunToCursor.inserted = (bpRunToCursor.bp.number != 0);
963 ValidateBreakpoint(bpRunToCursor);
970 if(ignoreBreakpoints)
971 GdbBreakpointsDelete(false);
975 if(ignoreBreakpoints)
976 GdbBreakpointsDelete(false);
977 GdbExecContinue(true);
983 void GetCallStackCursorLine(bool * error, int * lineCursor, int * lineTopFrame)
985 if(activeFrameLevel == -1)
993 *error = signalOn && activeThread == signalThread;
994 *lineCursor = activeFrameLevel + 1;
995 *lineTopFrame = activeFrameLevel ? 1 : 0;
999 int GetMarginIconsLineNumbers(char * fileName, int lines[], bool enabled[], int max, bool * error, int * lineCursor, int * lineTopFrame)
1001 char winFilePath[MAX_LOCATION];
1002 char * absoluteFilePath = GetSlashPathBuffer(winFilePath, fileName);
1004 Iterator<Breakpoint> it { ide.workspace.breakpoints };
1005 while(it.Next() && count < max)
1007 Breakpoint bp = it.data;
1010 if(bp.absoluteFilePath && bp.absoluteFilePath[0] && !fstrcmp(bp.absoluteFilePath, absoluteFilePath))
1012 lines[count] = bp.line;
1013 enabled[count] = bp.enabled;
1018 if(activeFrameLevel == -1)
1026 *error = signalOn && activeThread == signalThread;
1027 if(activeFrame && activeFrame.absoluteFile && !fstrcmp(absoluteFilePath, activeFrame.absoluteFile))
1028 *lineCursor = activeFrame.line;
1031 if(activeFrame && stopItem && stopItem.frame && activeFrame.level == stopItem.frame.level)
1033 else if(stopItem && stopItem.frame && stopItem.frame.absoluteFile && !fstrcmp(absoluteFilePath, stopItem.frame.absoluteFile))
1034 *lineTopFrame = stopItem.frame.line;
1038 if(*lineTopFrame == *lineCursor && *lineTopFrame)
1044 void ChangeWatch(DataRow row, char * expression)
1046 Watch wh = (Watch)row.tag;
1049 delete wh.expression;
1051 wh.expression = CopyString(expression);
1054 Iterator<Watch> it { ide.workspace.watches };
1056 ide.workspace.watches.Delete(it.pointer);
1063 ide.workspace.watches.Add(wh);
1065 wh.expression = CopyString(expression);
1067 ide.workspace.Save();
1068 //if(expression && state == stopped)
1073 void MoveIcons(char * fileName, int lineNumber, int move, bool start)
1075 char winFilePath[MAX_LOCATION];
1076 char * absoluteFilePath = GetSlashPathBuffer(winFilePath, fileName);
1079 for(bpLink = ide.workspace.breakpoints.first; bpLink; bpLink = next)
1081 Breakpoint bp = (Breakpoint)bpLink.data;
1084 if(bp.type == user && bp.absoluteFilePath && !fstrcmp(bp.absoluteFilePath, absoluteFilePath))
1086 if(bp.line > lineNumber || (bp.line == lineNumber && start))
1088 if(move < 0 && (bp.line < lineNumber - move))
1089 ide.workspace.RemoveBreakpoint(bp);
1093 ide.breakpointsView.UpdateBreakpoint(bp.row);
1094 ide.workspace.Save();
1100 // moving code cursors is futile, on next step, stop, hit, cursors will be offset anyways
1103 bool SourceDirDialog(char * title, char * startDir, char * test, char * sourceDir)
1107 String srcDir = null;
1109 debuggerFileDialog.text = title;
1110 debuggerFileDialog.currentDirectory = startDir;
1111 debuggerFileDialog.master = ide;
1113 while(debuggerFileDialog.Modal())
1115 strcpy(sourceDir, debuggerFileDialog.filePath);
1116 if(!fstrcmp(ide.workspace.projectDir, sourceDir) &&
1117 MessageBox { type = yesNo, master = ide,
1118 contents = $"This is the project directory.\nWould you like to try again?",
1119 text = $"Invalid Source Directory" }.Modal() == no)
1123 for(dir : ide.workspace.sourceDirs)
1125 if(!fstrcmp(dir, sourceDir))
1133 MessageBox { type = yesNo, master = ide,
1134 contents = $"This source directory is already specified.\nWould you like to try again?",
1135 text = $"Invalid Source Directory" }.Modal() == no)
1141 char file[MAX_LOCATION];
1142 strcpy(file, sourceDir);
1143 PathCat(file, test);
1144 result = FileExists(file);
1146 MessageBox { type = yesNo, master = ide,
1147 contents = $"Unable to locate source file.\nWould you like to try again?",
1148 text = $"Invalid Source Directory" }.Modal() == no)
1162 void AddSourceDir(char * sourceDir)
1164 ide.workspace.sourceDirs.Add(CopyString(sourceDir));
1165 ide.workspace.Save();
1169 DebuggerState oldState = state;
1174 GdbDebugBreak(true);
1177 GdbCommand(false, "-environment-directory \"%s\"", sourceDir);
1180 if(oldState == running)
1181 GdbExecContinue(false);
1185 void ToggleBreakpoint(char * fileName, int lineNumber, Project prj)
1187 char winFilePath[MAX_LOCATION];
1188 char * absoluteFilePath = GetSlashPathBuffer(winFilePath, fileName);
1189 char absolutePath[MAX_LOCATION];
1190 char relativePath[MAX_LOCATION];
1191 char sourceDir[MAX_LOCATION];
1192 Breakpoint bp = null;
1194 strcpy(absolutePath, absoluteFilePath);
1195 for(i : ide.workspace.breakpoints; i.type == user && i.absoluteFilePath && !fstrcmp(i.absoluteFilePath, absolutePath) && i.line == lineNumber)
1204 ide.workspace.RemoveBreakpoint(bp);
1212 // FIXED: This is how it should have been... Source locations are only for files not in project
1213 // if(eString_PathInsideOf(absolutePath, ide.workspace.projectDir))
1214 // MakePathRelative(absolutePath, ide.workspace.projectDir, relativePath);
1215 bool result = false;
1217 result = prj.GetRelativePath(absolutePath, relativePath);
1219 ide.projectView.GetRelativePath(absolutePath, relativePath);
1220 //if(ide.projectView.GetRelativePath(absolutePath, relativePath));
1224 char title[MAX_LOCATION];
1225 char directory[MAX_LOCATION];
1226 StripLastDirectory(absolutePath, directory);
1227 sprintf(title, $"Provide source files location directory for %s", absolutePath);
1230 String srcDir = null;
1231 for(dir : ide.workspace.sourceDirs)
1233 if(eString_PathInsideOf(absolutePath, dir))
1235 MakePathRelative(absoluteFilePath, dir, relativePath);
1243 if(SourceDirDialog(title, directory, null, sourceDir))
1245 if(eString_PathInsideOf(absolutePath, sourceDir))
1247 AddSourceDir(sourceDir);
1248 MakePathRelative(absoluteFilePath, sourceDir, relativePath);
1251 else if(MessageBox { type = yesNo, master = ide,
1252 contents = $"You must provide a valid source directory in order to place a breakpoint in this file.\nWould you like to try again?",
1253 text = $"Invalid Source Directory" }.Modal() == no)
1256 else if(MessageBox { type = yesNo, master = ide,
1257 contents = $"You must provide a source directory in order to place a breakpoint in this file.\nWould you like to try again?",
1258 text = $"No Source Directory Provided" }.Modal() == no)
1262 ide.workspace.bpCount++;
1263 bp = { line = lineNumber, type = user, enabled = true, level = -1 };
1264 ide.workspace.breakpoints.Add(bp);
1265 bp.absoluteFilePath = CopyString(absolutePath);
1266 bp.relativeFilePath = CopyString(relativePath);
1267 ide.breakpointsView.AddBreakpoint(bp);
1272 DebuggerState oldState = state;
1277 GdbDebugBreak(true);
1282 sentBreakInsert = true;
1283 GdbCommand(false, "-break-insert %s:%d", bp.relativeFilePath, bp.line);
1286 bp.inserted = (bp.bp && bp.bp.number != 0);
1287 ValidateBreakpoint(bp);
1291 if(oldState == running)
1292 GdbExecContinue(false);
1295 ide.workspace.Save();
1298 void UpdateRemovedBreakpoint(Breakpoint bp)
1300 if(targeted && bp.inserted)
1302 DebuggerState oldState = state;
1307 GdbDebugBreak(true);
1311 GdbCommand(false, "-break-delete %d", bp.bp.number);
1314 if(oldState == running)
1315 GdbExecContinue(false);
1321 void ParseFrame(Frame frame, char * string)
1324 Array<char *> frameTokens { minAllocSize = 50 };
1325 Array<char *> argsTokens { minAllocSize = 50 };
1326 Array<char *> argumentTokens { minAllocSize = 50 };
1327 DebugListItem item { };
1330 TokenizeList(string, ',', frameTokens);
1331 for(i = 0; i < frameTokens.count; i++)
1333 if(TokenizeListItem(frameTokens[i], item))
1335 StripQuotes(item.value, item.value);
1336 if(!strcmp(item.name, "level"))
1337 frame.level = atoi(item.value);
1338 else if(!strcmp(item.name, "addr"))
1339 frame.addr = CopyString(item.value);
1340 else if(!strcmp(item.name, "func"))
1341 frame.func = CopyString(item.value);
1342 else if(!strcmp(item.name, "args"))
1344 if(!strcmp(item.value, "[]"))
1345 frame.argsCount = 0;
1348 item.value = StripBrackets(item.value);
1349 TokenizeList(item.value, ',', argsTokens);
1350 for(j = 0; j < argsTokens.count; j++)
1352 argsTokens[j] = StripCurlies(argsTokens[j]);
1353 TokenizeList(argsTokens[j], ',', argumentTokens);
1354 for(k = 0; k < argumentTokens.count; k++)
1357 frame.args.Add(arg);
1358 if(TokenizeListItem(argumentTokens[k], item))
1360 if(!strcmp(item.name, "name"))
1362 StripQuotes(item.value, item.value);
1363 arg.name = CopyString(item.value);
1365 else if(!strcmp(item.name, "value"))
1367 StripQuotes(item.value, item.value);
1368 arg.value = CopyString(item.value);
1371 DebuggerProtocolUnknown("Unknown frame args item name", item.name);
1374 DebuggerProtocolUnknown("Bad frame args item", "");
1376 argumentTokens.RemoveAll();
1378 frame.argsCount = argsTokens.count;
1379 argsTokens.RemoveAll();
1382 else if(!strcmp(item.name, "from"))
1383 frame.from = item.value;
1384 else if(!strcmp(item.name, "file"))
1386 frame.file = item.value;
1387 frame.absoluteFile = ide.workspace.GetAbsolutePathFromRelative(frame.file);
1389 else if(!strcmp(item.name, "line"))
1390 frame.line = atoi(item.value);
1391 else if(!strcmp(item.name, "fullname"))
1393 // New GDB is giving us a full name... Any reason why we coudln't figure it out ourselves?
1396 DebuggerProtocolUnknown("Unknown frame member name", item.name);
1399 DebuggerProtocolUnknown("Bad frame", "");
1404 delete argumentTokens;
1408 void ShowDebuggerViews()
1410 ide.outputView.Show();
1411 ide.outputView.SelectTab(debug);
1412 ide.threadsView.Show();
1413 ide.callStackView.Show();
1414 ide.watchesView.Show();
1418 void HideDebuggerViews()
1420 ide.RepositionWindows(true);
1423 void ::GdbCommand(bool focus, char * format, ...)
1427 char string[MAX_F_STRING];
1430 va_start(args, format);
1431 vsprintf(string, format, args);
1435 ide.debugger.serialSemaphore.TryWait();
1438 #ifdef GDB_DEBUG_CONSOLE
1439 Log(string); Log("\n");
1441 #ifdef GDB_DEBUG_OUTPUT
1442 ide.outputView.gdbBox.Logf("cmd: %s\n", string);
1444 #ifdef GDB_DEBUG_GUI
1446 ide.gdbDialog.AddCommand(string);
1448 gdbHandle.Printf("%s\n", string);
1451 Process_ShowWindows(targetProcessId);
1454 ide.debugger.serialSemaphore.Wait();
1459 bool ValidateBreakpoint(Breakpoint bp)
1463 if(bp.bp.line != bp.line)
1468 ide.outputView.debugBox.Logf("WOULD HAVE -- Invalid breakpoint disabled: %s:%d\n", bp.relativeFilePath, bp.line);
1472 //GdbCommand(false, "-break-delete %d", bp.bp.number);
1473 //bp.inserted = false;
1475 //bp.enabled = false;
1480 ide.outputView.debugBox.Logf("Debugger Error: ValidateBreakpoint error\n");
1481 bp.line = bp.bp.line;
1488 static void GdbInsertInternalBreakpoint()
1492 //if(!breakpointsInserted)
1494 DirExpression objDir = ide.project.GetObjDir(currentCompiler, prjConfig);
1499 if(bp.type == internalMain)
1501 sentBreakInsert = true;
1502 GdbCommand(false, "-break-insert main");
1505 bp.inserted = (bp.bp && bp.bp.number != 0);
1507 #if defined(__WIN32__)
1508 else if(bp.type == internalWinMain)
1510 sentBreakInsert = true;
1511 GdbCommand(false, "-break-insert WinMain");
1514 bp.inserted = (bp.bp && bp.bp.number != 0);
1517 else if(bp.type == internalModulesLoaded)
1519 char path[MAX_LOCATION];
1520 char name[MAX_LOCATION];
1521 char fixedModuleName[MAX_FILENAME];
1524 bool moduleLoadBlock = false;
1526 ReplaceSpaces(fixedModuleName, ide.project.moduleName);
1527 sprintf(name, "%s.main.ec", fixedModuleName);
1528 strcpy(path, ide.workspace.projectDir);
1529 PathCatSlash(path, objDir.dir);
1530 PathCatSlash(path, name);
1531 f = FileOpen(path, read);
1534 for(lineNumber = 1; !f.Eof(); lineNumber++)
1536 if(f.GetLine(line, sizeof(line) - 1))
1538 bool moduleLoadLine;
1539 TrimLSpaces(line, line);
1540 moduleLoadLine = !strncmp(line, "eModule_Load", strlen("eModule_Load"));
1541 if(!moduleLoadBlock && moduleLoadLine)
1542 moduleLoadBlock = true;
1543 else if(moduleLoadBlock && !moduleLoadLine && strlen(line) > 0)
1549 char relative[MAX_LOCATION];
1550 bp.absoluteFilePath = CopyString(path);
1551 MakePathRelative(path, ide.workspace.projectDir, relative);
1552 delete bp.relativeFilePath;
1553 bp.relativeFilePath = CopyString(relative);
1554 bp.line = lineNumber;
1555 sentBreakInsert = true;
1556 GdbCommand(false, "-break-insert %s:%d", bp.relativeFilePath, lineNumber);
1559 bp.inserted = (bp.bp && bp.bp.number != 0);
1560 ValidateBreakpoint(bp);
1573 void GdbBreakpointsInsert()
1577 //if(!breakpointsInserted)
1579 //if(!ignoreBreakpoints)
1580 //breakpointsInserted = true;
1581 for(bp : ide.workspace.breakpoints)
1583 if(!bp.inserted && bp.type == user)
1585 if(!ignoreBreakpoints && bp.enabled)
1587 sentBreakInsert = true;
1588 GdbCommand(false, "-break-insert %s:%d", bp.relativeFilePath, bp.line);
1591 bp.inserted = (bp.bp && bp.bp.number != 0);
1594 ValidateBreakpoint(bp);
1600 printf("problem\n");
1602 bp.bp = GdbDataBreakpoint { };
1606 if(bpRunToCursor && !bpRunToCursor.inserted)
1608 sentBreakInsert = true;
1609 GdbCommand(false, "-break-insert %s:%d", bpRunToCursor.relativeFilePath, bpRunToCursor.line);
1610 bpRunToCursor.bp = bpItem;
1612 bpRunToCursor.inserted = (bpRunToCursor.bp && bpRunToCursor.bp.number != 0);
1613 ValidateBreakpoint(bpRunToCursor);
1619 void GdbBreakpointsDelete(bool deleteRunToCursor)
1621 //breakpointsInserted = false;
1624 for(bp : ide.workspace.breakpoints)
1627 GdbCommand(false, "-break-delete %d", bp.bp.number);
1628 bp.inserted = false;
1630 //check here (reply form -break-delete, returns bpitem?)
1633 if(deleteRunToCursor && bpRunToCursor)
1635 GdbCommand(false, "-break-delete %d", bpRunToCursor.bp.number);
1636 bpRunToCursor.inserted = false;
1637 bpRunToCursor.bp = bpItem;
1638 //check here (reply form -break-delete, returns bpitem?)
1647 stackFrames.Free(Frame::Free);
1648 GdbCommand(false, "-stack-info-depth");
1650 GdbCommand(false, "-stack-info-depth 192");
1651 if(frameCount && frameCount <= 192)
1652 GdbCommand(false, "-stack-list-frames 0 191");
1655 GdbCommand(false, "-stack-list-frames 0 95");
1656 GdbCommand(false, "-stack-list-frames %d %d", Max(frameCount - 96, 96), frameCount - 1);
1658 GdbCommand(false, "");
1665 char escaped[MAX_LOCATION];
1666 strescpy(escaped, targetFile);
1667 GdbCommand(false, "file \"%s\"", escaped); //GDB/MI Missing Implementation -symbol-file, -target-attach
1672 for(prj : ide.workspace.projects)
1674 if(prj == ide.workspace.projects.firstIterator.data)
1677 //PrintLn("THIS: ", (String)prj.topNode.path);
1678 GdbCommand(false, "-environment-directory \"%s\"", prj.topNode.path);
1679 //GdbCommand(false, ""); // why this empty GDB command
1682 for(dir : ide.workspace.sourceDirs)
1684 GdbCommand(false, "-environment-directory \"%s\"", dir);
1685 //GdbCommand(false, ""); // why this empty GDB command
1687 GdbInsertInternalBreakpoint();
1693 void GdbTargetRelease()
1697 GdbBreakpointsDelete(true);
1698 GdbCommand(false, "file"); //GDB/MI Missing Implementation -target-detach
1704 void GdbDebugBreak(bool internal)
1709 breakType = DebuggerAction::internal;
1711 if(ide) ide.Update(null);
1713 if(Process_Break(targetProcessId)) //GdbCommand(false, "-exec-interrupt");
1714 serialSemaphore.Wait();
1717 ChangeState(loaded);
1718 targetProcessId = 0;
1723 ide.outputView.debugBox.Logf("Debugger Error: GdbDebugBreak with not target id should never happen\n");
1730 ShowDebuggerViews();
1731 GdbCommand(true, "-exec-run");
1734 void GdbExecContinue(bool focus)
1737 GdbCommand(focus, "-exec-continue");
1743 GdbCommand(true, "-exec-next");
1749 GdbCommand(true, "-exec-step");
1752 void GdbExecFinish()
1755 GdbCommand(true, "-exec-finish");
1758 void GdbExecCommon()
1760 ClearBreakDisplay();
1761 GdbBreakpointsInsert();
1764 #ifdef GDB_DEBUG_GUI
1765 void SendGDBCommand(char * command)
1767 DebuggerState oldState = state;
1772 GdbDebugBreak(true);
1775 GdbCommand(false, command);
1778 if(oldState == running)
1779 GdbExecContinue(false);
1783 void ClearBreakDisplay()
1786 activeFrameLevel = -1;
1797 stackFrames.Free(Frame::Free);
1798 WatchesCodeEditorLinkRelease();
1799 ide.callStackView.Clear();
1800 ide.threadsView.Clear();
1807 GdbCommand(false, "-interpreter-exec console \"kill\""); // should use -exec-abort -- GDB/MI implementation incomplete
1811 bool GdbInit(CompilerConfig compiler, ProjectConfig config)
1814 char oldDirectory[MAX_LOCATION];
1815 char tempPath[MAX_LOCATION];
1816 char command[MAX_LOCATION];
1817 Project project = ide.project;
1818 DirExpression targetDirExp = project.GetTargetDir(compiler, config);
1819 PathBackup pathBackup { };
1821 if(currentCompiler != compiler)
1823 delete currentCompiler;
1824 currentCompiler = compiler;
1825 incref currentCompiler;
1829 ChangeState(loaded);
1831 sentBreakInsert = false;
1835 //breakpointsInserted = false;
1837 ide.outputView.ShowClearSelectTab(debug);
1838 ide.outputView.debugBox.Logf($"Starting debug mode\n");
1840 #ifdef GDB_DEBUG_CONSOLE
1841 Log("Starting GDB"); Log("\n");
1843 #ifdef GDB_DEBUG_OUTPUT
1844 ide.outputView.gdbBox.Logf("run: Starting GDB\n");
1847 strcpy(tempPath, ide.workspace.projectDir);
1848 PathCatSlash(tempPath, targetDirExp.dir);
1850 targetDir = CopyString(tempPath);
1851 project.CatTargetFileName(tempPath, compiler, config);
1853 targetFile = CopyString(tempPath);
1855 GetWorkingDir(oldDirectory, MAX_LOCATION);
1856 if(ide.workspace.debugDir && ide.workspace.debugDir[0])
1858 char temp[MAX_LOCATION];
1859 strcpy(temp, ide.workspace.projectDir);
1860 PathCatSlash(temp, ide.workspace.debugDir);
1861 ChangeWorkingDir(temp);
1864 ChangeWorkingDir(ide.workspace.projectDir);
1866 ide.SetPath(true, compiler, config);
1868 // TODO: This pollutes the environment, but at least it works
1869 // It shouldn't really affect the IDE as the PATH gets restored and other variables set for testing will unlikely cause problems
1870 // What is the proper solution for this? DualPipeOpenEnv?
1871 // gdb set environment commands don't seem to take effect
1872 for(e : ide.workspace.environmentVars)
1874 SetEnvironment(e.name, e.string);
1877 sprintf(command, "gdb -n -silent --interpreter=mi2"); //-async //\"%s\"
1879 gdbHandle = DualPipeOpen(PipeOpenMode { output = 1, error = 2, input = 1 }, command);
1882 ide.outputView.debugBox.Logf($"Debugger Fatal Error: Couldn't start GDB\n");
1890 gdbProcessId = gdbHandle.GetProcessID();
1893 ide.outputView.debugBox.Logf($"Debugger Fatal Error: Couldn't get GDB process ID\n");
1899 serialSemaphore.Wait();
1904 //ChangeState(terminated);
1910 #if defined(__unix__)
1912 CreateTemporaryDir(progFifoDir, "ecereide");
1913 strcpy(progFifoPath, progFifoDir);
1914 PathCat(progFifoPath, "ideprogfifo");
1915 if(!mkfifo(progFifoPath, 0600))
1917 //fileCreated = true;
1922 ide.outputView.debugBox.Logf($"err: Unable to create FIFO %s\n", progFifoPath);
1927 progThread.terminate = false;
1928 progThread.Create();
1931 #if defined(__WIN32__)
1932 GdbCommand(false, "-gdb-set new-console on");
1935 GdbCommand(false, "-gdb-set verbose off");
1936 //GdbCommand(false, "-gdb-set exec-done-display on");
1937 GdbCommand(false, "-gdb-set step-mode off");
1938 GdbCommand(false, "-gdb-set unwindonsignal on");
1939 //GdbCommand(false, "-gdb-set shell on");
1940 GdbCommand(false, "set print elements 992");
1941 GdbCommand(false, "-gdb-set backtrace limit 100000");
1943 #if defined(__unix__)
1944 GdbCommand(false, "-inferior-tty-set %s", progFifoPath);
1947 GdbCommand(false, "-gdb-set args %s", ide.workspace.commandLineArgs ? ide.workspace.commandLineArgs : "");
1949 for(e : ide.workspace.environmentVars)
1951 GdbCommand(false, "set environment %s=%s", e.name, e.string);
1958 ChangeWorkingDir(oldDirectory);
1964 delete targetDirExp;
1970 if(gdbHandle && gdbProcessId)
1972 GdbCommand(false, "-gdb-exit");
1987 ChangeState(terminated); // this state change seems to be superfluous, is it safety for something?
1991 for(bp : ide.workspace.breakpoints)
1992 bp.inserted = false;
1994 bp.inserted = false;
1996 bpRunToCursor.inserted = false;
1998 ide.outputView.debugBox.Logf($"Debugging stopped\n");
1999 ClearBreakDisplay();
2002 #if defined(__unix__)
2003 if(FileExists(progFifoPath)) //fileCreated)
2005 progThread.terminate = true;
2008 fifoFile.CloseInput();
2014 DeleteFile(progFifoPath);
2015 progFifoPath[0] = '\0';
2021 void WatchesCodeEditorLinkInit()
2024 char tempPath[MAX_LOCATION];
2025 char path[MAX_LOCATION];
2027 //void MakeFilePathProjectRelative(char * path, char * relativePath)
2028 if(!ide.projectView.GetRelativePath(activeFrame.file, tempPath))
2029 strcpy(tempPath, activeFrame.file);
2031 strcpy(path, ide.workspace.projectDir);
2032 PathCat(path, tempPath);
2033 codeEditor = (CodeEditor)ide.OpenFile(path, Normal, false, null, no);
2036 for(srcDir : ide.workspace.sourceDirs)
2038 strcpy(path, srcDir);
2039 PathCat(path, tempPath);
2040 codeEditor = (CodeEditor)ide.OpenFile(path, Normal, false, null, no);
2041 if(codeEditor) break;
2046 if(activeFrame && !activeFrame.absoluteFile && activeFrame.file)
2047 activeFrame.absoluteFile = ide.workspace.GetAbsolutePathFromRelative(activeFrame.file);
2048 if(!activeFrame || !activeFrame.absoluteFile)
2051 codeEditor = (CodeEditor)ide.OpenFile(activeFrame.absoluteFile, normal, false, null, no, normal);
2054 codeEditor.inUseDebug = true;
2057 //watchesInit = true;
2060 void WatchesCodeEditorLinkRelease()
2066 codeEditor.inUseDebug = false;
2067 if(!codeEditor.visible)
2068 codeEditor.Destroy(0);
2074 bool ResolveWatch(Watch wh)
2076 bool result = false;
2089 char watchmsg[MAX_F_STRING];
2090 if(state == stopped && !codeEditor)
2091 wh.value = CopyString($"No source file found for selected frame");
2092 //if(codeEditor && state == stopped || state != stopped)
2095 Module backupPrivateModule;
2096 Context backupContext;
2097 Class backupThisClass;
2101 backupPrivateModule = GetPrivateModule();
2102 backupContext = GetCurrentContext();
2103 backupThisClass = GetThisClass();
2106 SetPrivateModule(codeEditor.privateModule);
2107 SetCurrentContext(codeEditor.globalContext);
2108 SetTopContext(codeEditor.globalContext);
2109 SetGlobalContext(codeEditor.globalContext);
2110 SetGlobalData(&codeEditor.globalData);
2113 exp = ParseExpressionString(wh.expression);
2115 if(exp && !parseError)
2117 if(GetPrivateModule())
2120 DebugFindCtxTree(codeEditor.ast, activeFrame.line, 0);
2121 ProcessExpressionType(exp);
2123 wh.type = exp.expType;
2126 DebugComputeExpression(exp);
2128 /*if(exp.hasAddress)
2130 char temp[MAX_F_STRING];
2131 sprintf(temp, "0x%x", exp.address);
2132 wh.address = CopyString(temp);
2133 // wh.address = CopyStringf("0x%x", exp.address);
2138 Type dataType = exp.expType;
2141 char temp[MAX_F_STRING];
2142 switch(dataType.kind)
2145 sprintf(temp, "%i", exp.val.c);
2148 sprintf(temp, "%i", exp.val.s);
2153 sprintf(temp, "%i", exp.val.i);
2156 sprintf(temp, "%i", exp.val.i64);
2159 sprintf(temp, "%i", exp.val.p);
2164 long v = (long)exp.val.f;
2165 sprintf(temp, "%i", v);
2170 long v = (long)exp.val.d;
2171 sprintf(temp, "%i", v);
2176 wh.intVal = CopyString(temp);
2177 switch(dataType.kind)
2180 sprintf(temp, "0x%x", exp.val.c);
2183 sprintf(temp, "0x%x", exp.val.s);
2187 sprintf(temp, "0x%x", exp.val.i);
2190 sprintf(temp, "0x%x", exp.val.i64);
2193 sprintf(temp, "0x%x", exp.val.i64);
2196 sprintf(temp, "0x%x", exp.val.p);
2201 long v = (long)exp.val.f;
2202 sprintf(temp, "0x%x", v);
2207 long v = (long)exp.val.d;
2208 sprintf(temp, "0x%x", v);
2213 wh.hexVal = CopyString(temp);
2214 switch(dataType.kind)
2217 sprintf(temp, "0o%o", exp.val.c);
2220 sprintf(temp, "0o%o", exp.val.s);
2224 sprintf(temp, "0o%o", exp.val.i);
2227 sprintf(temp, "0o%o", exp.val.i64);
2230 sprintf(temp, "0o%o", exp.val.i64);
2233 sprintf(temp, "0o%o", exp.val.p);
2238 long v = (long)exp.val.f;
2239 sprintf(temp, "0o%o", v);
2244 long v = (long)exp.val.d;
2245 sprintf(temp, "0o%o", v);
2250 wh.octVal = CopyString(temp);
2253 // WHATS THIS HERE ?
2254 if(exp.type == constantExp && exp.constant)
2255 wh.constant = CopyString(exp.constant);
2261 case symbolErrorExp:
2262 sprintf(watchmsg, $"Symbol \"%s\" not found", exp.identifier.string);
2264 case structMemberSymbolErrorExp:
2265 // todo get info as in next case (ExpClassMemberSymbolError)
2266 sprintf(watchmsg, $"Error: Struct member not found for \"%s\"", wh.expression);
2268 case classMemberSymbolErrorExp:
2271 Expression memberExp = exp.member.exp;
2272 Identifier memberID = exp.member.member;
2273 Type type = memberExp.expType;
2276 _class = (memberID && memberID.classSym) ? memberID.classSym.registered : ((type.kind == classType && type._class) ? type._class.registered : null);
2279 char string[256] = "";
2281 PrintType(type, string, false, true);
2282 classSym = FindClass(string);
2283 _class = classSym ? classSym.registered : null;
2286 sprintf(watchmsg, $"Member \"%s\" not found in class \"%s\"", memberID ? memberID.string : "", _class.name);
2288 sprintf(watchmsg, "Member \"%s\" not found in unregistered class? (Should never get this message)", memberID ? memberID.string : "");
2291 sprintf(watchmsg, "Member \"%s\" not found in no type? (Should never get this message)", memberID ? memberID.string : "");
2294 case memoryErrorExp:
2295 // Need to ensure when set to memoryErrorExp, constant is set
2296 sprintf(watchmsg, $"Memory can't be read at %s", /*(exp.type == constantExp) ? */exp.constant /*: null*/);
2298 case dereferenceErrorExp:
2299 sprintf(watchmsg, $"Dereference failure for \"%s\"", wh.expression);
2301 case unknownErrorExp:
2302 sprintf(watchmsg, $"Unknown error for \"%s\"", wh.expression);
2304 case noDebuggerErrorExp:
2305 sprintf(watchmsg, $"Debugger required for symbol evaluation in \"%s\"", wh.expression);
2307 case debugStateErrorExp:
2308 sprintf(watchmsg, $"Incorrect debugger state for symbol evaluation in \"%s\"", wh.expression);
2311 sprintf(watchmsg, $"Null type for \"%s\"", wh.expression);
2315 // Temporary Code for displaying Strings
2316 if((exp.expType && ((exp.expType.kind == pointerType ||
2317 exp.expType.kind == arrayType) && exp.expType.type.kind == charType)) ||
2318 (wh.type && wh.type.kind == classType && wh.type._class &&
2319 wh.type._class.registered && wh.type._class.registered.type == normalClass &&
2320 !strcmp(wh.type._class.registered.name, "String")))
2323 if(exp.expType.kind != arrayType || exp.hasAddress)
2329 //char temp[MAX_F_STRING * 32];
2331 ExpressionType evalError = dummyExp;
2332 /*if(exp.expType.kind == arrayType)
2333 sprintf(temp, "(char*)0x%x", exp.address);
2335 sprintf(temp, "(char*)%s", exp.constant);*/
2337 //evaluation = Debugger::EvaluateExpression(temp, &evalError);
2338 address = strtoul(exp.constant, null, 0);
2339 //printf("%x\n", address);
2340 sprintf(value, "0x%08x ", address);
2343 strcat(value, $"Null string");
2347 len = strlen(value);
2349 while(!string && size > 2)
2351 string = GdbReadMemory(address, size);
2354 if(string && string[0])
2357 if(UTF8Validate(string))
2362 for(c = 0; (ch = string[c]) && c<4096; c++)
2365 value[len++] = '\0';
2370 ISO8859_1toUTF8(string, value + len, 4096 - len - 30);
2371 strcat(value, ") (ISO8859-1)");
2378 strcat(value, $"Empty string");
2382 strcat(value, $"Couldn't read memory");
2384 wh.value = CopyString(value);
2387 else if(wh.type && wh.type.kind == classType && wh.type._class &&
2388 wh.type._class.registered && wh.type._class.registered.type == enumClass)
2390 uint64 value = strtoul(exp.constant, null, 0);
2391 Class enumClass = eSystem_FindClass(GetPrivateModule(), wh.type._class.registered.name);
2392 EnumClassData enumeration = (EnumClassData)enumClass.data;
2394 for(item = enumeration.values.first; item; item = item.next)
2395 if((int)item.data == value)
2398 wh.value = CopyString(item.name);
2400 wh.value = CopyString($"Invalid Enum Value");
2401 result = (bool)atoi(exp.constant);
2403 else if(wh.type && (wh.type.kind == charType || (wh.type.kind == classType && wh.type._class &&
2404 wh.type._class.registered && !strcmp(wh.type._class.registered.fullName, "ecere::com::unichar"))) )
2411 if(exp.constant[0] == '\'')
2413 if((int)((byte *)exp.constant)[1] > 127)
2416 value = UTF8GetChar(exp.constant + 1, &nb);
2417 if(nb < 2) value = exp.constant[1];
2418 signedValue = value;
2422 signedValue = exp.constant[1];
2424 // Precomp Syntax error with boot strap here:
2425 byte b = (byte)(char)signedValue;
2426 value = (unichar) b;
2432 if(wh.type.kind == charType && wh.type.isSigned)
2434 signedValue = (int)(char)strtol(exp.constant, null, 0);
2436 // Precomp Syntax error with boot strap here:
2437 byte b = (byte)(char)signedValue;
2438 value = (unichar) b;
2443 value = strtoul(exp.constant, null, 0);
2444 signedValue = (int)value;
2448 UTF32toUTF8Len(&value, 1, charString, 5);
2450 sprintf(string, "\'\\0' (0)");
2451 else if(value == '\t')
2452 sprintf(string, "\'\\t' (%d)", value);
2453 else if(value == '\n')
2454 sprintf(string, "\'\\n' (%d)", value);
2455 else if(value == '\r')
2456 sprintf(string, "\'\\r' (%d)", value);
2457 else if(wh.type.kind == charType && wh.type.isSigned)
2458 sprintf(string, "\'%s\' (%d)", charString, signedValue);
2459 else if(value > 256 || wh.type.kind != charType)
2461 if(value > 0x10FFFF || !GetCharCategory(value))
2462 sprintf(string, $"Invalid Unicode Keypoint (0x%08X)", value);
2464 sprintf(string, "\'%s\' (U+%04X)", charString, value);
2467 sprintf(string, "\'%s\' (%d)", charString, value);
2469 wh.value = CopyString(string);
2474 wh.value = CopyString(exp.constant);
2475 result = (bool)atoi(exp.constant);
2481 wh.value = PrintHexUInt(exp.address);
2482 result = (bool)exp.address;
2486 char tempString[256];
2487 if(exp.member.memberType == propertyMember)
2488 sprintf(watchmsg, $"Missing property evaluation support for \"%s\"", wh.expression);
2490 sprintf(watchmsg, $"Evaluation failed for \"%s\" of type \"%s\"", wh.expression,
2491 exp.type.OnGetString(tempString, null, null));
2497 sprintf(watchmsg, $"Invalid expression: \"%s\"", wh.expression);
2498 if(exp) FreeExpression(exp);
2501 SetPrivateModule(backupPrivateModule);
2502 SetCurrentContext(backupContext);
2503 SetTopContext(backupContext);
2504 SetGlobalContext(backupContext);
2505 SetThisClass(backupThisClass);
2508 // wh.value = CopyString("No source file found for selected frame");
2511 wh.value = CopyString(watchmsg);
2513 ide.watchesView.UpdateWatch(wh);
2517 void EvaluateWatches()
2519 for(wh : ide.workspace.watches)
2523 char * ::GdbEvaluateExpression(char * expression)
2527 GdbCommand(false, "-data-evaluate-expression \"%s\"", expression);
2529 ide.outputView.debugBox.Logf("Debugger Error: GdbEvaluateExpression\n");
2533 // to be removed... use GdbReadMemory that returns a byte array instead
2534 char * ::GdbReadMemoryString(uint address, int size, char format, int rows, int cols)
2540 printf("GdbReadMemoryString called with size = 0!\n");
2542 GdbCommand(false, "-data-read-memory 0x%08x %c, %d, %d, %d", address, format, size, rows, cols);
2544 ide.outputView.debugBox.Logf("Debugger Error: GdbReadMemoryString\n");
2548 byte * ::GdbReadMemory(uint address, int bytes)
2552 GdbCommand(false, "-data-read-memory 0x%08x %c, 1, 1, %d", address, 'u', bytes);
2555 printf("GdbReadMemory called with bytes = 0!\n");
2558 ide.outputView.debugBox.Logf("Debugger Error: GdbReadMemory\n");
2559 else if(eval.result && strcmp(eval.result, "N/A"))
2561 byte * result = new byte[bytes];
2562 byte * string = eval.result;
2566 result[c++] = (byte)strtol(string, &string, 10);
2582 void EventHit(GdbDataStop stopItem)
2584 bool conditionMet = true;
2585 Breakpoint bp = bpHit;
2587 if(!bp && bpRunToCursor)
2591 GdbCommand(false, "-break-delete %d", bp.bp.number);
2596 if(bp.type == user && bp.line != stopItem.frame.line)
2598 bp.line = stopItem.frame.line;
2599 ide.breakpointsView.UpdateBreakpoint(bp.row);
2600 ide.workspace.Save();
2606 case internalWinMain:
2607 GdbBreakpointsInsert();
2608 if(userBreakOnInternBreak)
2610 userBreakOnInternBreak = false;
2611 // Why was SelectFrame missing here?
2612 SelectFrame(activeFrameLevel);
2613 GoToStackFrameLine(activeFrameLevel, true);
2618 GdbExecContinue(false);
2620 case internalModulesLoaded:
2622 GdbBreakpointsInsert();
2623 GdbExecContinue(false);
2628 conditionMet = ResolveWatch(bp.condition);
2630 if((bp.level == -1 || bp.level == frameCount-1) && conditionMet)
2635 ignoreBreakpoints = false;
2636 // Why was SelectFrame missing here?
2637 SelectFrame(activeFrameLevel);
2638 GoToStackFrameLine(activeFrameLevel, true);
2641 if(bp.type == BreakpointType::runToCursor)
2643 delete bpRunToCursor;
2644 bpRunToCursor = null;
2650 GdbExecContinue(false);
2654 GdbExecContinue(false);
2655 ide.breakpointsView.UpdateBreakpoint(bp.row);
2660 ide.outputView.debugBox.Logf("Debugger Error: Breakpoint hit could not match breakpoint instance\n");
2663 void GdbThreadExit()
2665 if(state != terminated)
2667 ChangeState(terminated);
2668 targetProcessId = 0;
2669 ClearBreakDisplay();
2673 serialSemaphore.Release();
2678 ide.outputView.debugBox.Logf($"Debugger Fatal Error: GDB lost\n");
2679 ide.outputView.debugBox.Logf($"Debugging stopped\n");
2682 //ChangeState(terminated);
2686 void GdbThreadMain(char * output)
2689 Array<char *> outTokens { minAllocSize = 50 };
2690 Array<char *> subTokens { minAllocSize = 50 };
2691 DebugListItem item { };
2692 DebugListItem item2 { };
2693 bool setWaitingForPID = false;
2695 #if defined(GDB_DEBUG_CONSOLE) || defined(GDB_DEBUG_GUI)
2696 #ifdef GDB_DEBUG_CONSOLE
2697 Log(output); Log("\n");
2699 #ifdef GDB_DEBUG_OUTPUT
2701 int len = strlen(output);
2709 for(c = 0; c < len / 1024; c++)
2711 strncpy(tmp, start, 1024);
2712 ide.outputView.gdbBox.Logf("out: %s\n", tmp);
2715 ide.outputView.gdbBox.Logf("out: %s\n", start);
2719 ide.outputView.gdbBox.Logf("out: %s\n", output);
2723 #ifdef GDB_DEBUG_CONSOLE
2724 strcpy(lastGdbOutput, output);
2726 #ifdef GDB_DEBUG_GUI
2727 if(ide.gdbDialog) ide.gdbDialog.AddOutput(output);
2734 if(strstr(output, "No debugging symbols found") || strstr(output, "(no debugging symbols found)"))
2737 ide.outputView.debugBox.Logf($"Target doesn't contain debug information!\n");
2743 if(TokenizeList(output, ',', outTokens) && !strcmp(outTokens[0], "^done"))
2745 //if(outTokens.count == 1)
2750 ChangeState(loaded);
2751 targetProcessId = 0;
2752 if(outTokens.count > 1 && TokenizeListItem(outTokens[1], item))
2754 if(!strcmp(item.name, "reason"))
2756 char * reason = item.value;
2757 StripQuotes(reason, reason);
2758 if(!strcmp(reason, "exited-normally") || !strcmp(reason, "exited") || !strcmp(reason, "exited-signalled"))
2761 if(outTokens.count > 2 && TokenizeListItem(outTokens[2], item2))
2763 StripQuotes(item2.value, item2.value);
2764 if(!strcmp(item2.name, "exit-code"))
2765 exitCode = item2.value;
2771 HandleExit(reason, exitCode);
2775 DebuggerProtocolUnknown("Unknown kill reply", item.name);
2778 HandleExit(null, null);
2781 if(outTokens.count > 1 && TokenizeListItem(outTokens[1], item))
2783 if(!strcmp(item.name, "bkpt"))
2785 sentBreakInsert = false;
2788 printf("problem\n");
2790 bpItem = GdbDataBreakpoint { };
2791 item.value = StripCurlies(item.value);
2792 TokenizeList(item.value, ',', subTokens);
2793 for(i = 0; i < subTokens.count; i++)
2795 if(TokenizeListItem(subTokens[i], item))
2797 StripQuotes(item.value, item.value);
2798 if(!strcmp(item.name, "number"))
2799 bpItem.number = atoi(item.value);
2800 else if(!strcmp(item.name, "type"))
2801 bpItem.type = CopyString(item.value);
2802 else if(!strcmp(item.name, "disp"))
2803 bpItem.disp = CopyString(item.value);
2804 else if(!strcmp(item.name, "enabled"))
2805 bpItem.enabled = (!strcmpi(item.value, "y"));
2806 else if(!strcmp(item.name, "addr"))
2807 bpItem.addr = CopyString(item.value);
2808 else if(!strcmp(item.name, "func"))
2809 bpItem.func = CopyString(item.value);
2810 else if(!strcmp(item.name, "file"))
2811 bpItem.file = item.value;
2812 else if(!strcmp(item.name, "line"))
2813 bpItem.line = atoi(item.value);
2814 else if(!strcmp(item.name, "at"))
2815 bpItem.at = CopyString(item.value);
2816 else if(!strcmp(item.name, "times"))
2817 bpItem.times = atoi(item.value);
2820 //breakType = bpValidation;
2821 //app.SignalEvent();
2822 subTokens.RemoveAll();
2824 else if(!strcmp(item.name, "BreakpointTable"))
2825 ide.outputView.debugBox.Logf("Debugger Error: Command reply BreakpointTable not handled\n");
2826 else if(!strcmp(item.name, "depth"))
2828 StripQuotes(item.value, item.value);
2829 frameCount = atoi(item.value);
2831 stackFrames.Free(Frame::Free);
2833 else if(!strcmp(item.name, "stack"))
2836 if(stackFrames.count)
2837 ide.callStackView.Logf("...\n");
2840 item.value = StripBrackets(item.value);
2841 TokenizeList(item.value, ',', subTokens);
2842 for(i = 0; i < subTokens.count; i++)
2844 if(TokenizeListItem(subTokens[i], item))
2846 if(!strcmp(item.name, "frame"))
2849 stackFrames.Add(frame);
2850 item.value = StripCurlies(item.value);
2851 ParseFrame(frame, item.value);
2852 if(frame.file && frame.from)
2853 DebuggerProtocolUnknown("Unexpected frame file and from members present", "");
2857 if(activeFrameLevel == -1)
2859 if(ide.projectView.IsModuleInProject(frame.file));
2861 if(frame.level != 0)
2863 //stopItem.frame = frame;
2864 breakType = selectFrame;
2867 activeFrame = frame;
2868 activeFrameLevel = frame.level;
2871 ide.callStackView.Logf("%3d ", frame.level);
2872 if(!strncmp(frame.func, "__ecereMethod_", strlen("__ecereMethod_")))
2873 ide.callStackView.Logf($"%s Method, %s:%d\n", &frame.func[strlen("__ecereMethod_")], (s = CopySystemPath(frame.file)), frame.line);
2874 else if(!strncmp(frame.func, "__ecereProp_", strlen("__ecereProp_")))
2875 ide.callStackView.Logf($"%s Property, %s:%d\n", &frame.func[strlen("__ecereProp_")], (s = CopySystemPath(frame.file)), frame.line);
2876 else if(!strncmp(frame.func, "__ecereConstructor_", strlen("__ecereConstructor_")))
2877 ide.callStackView.Logf($"%s Constructor, %s:%d\n", &frame.func[strlen("__ecereConstructor_")], (s = CopySystemPath(frame.file)), frame.line);
2878 else if(!strncmp(frame.func, "__ecereDestructor_", strlen("__ecereDestructor_")))
2879 ide.callStackView.Logf($"%s Destructor, %s:%d\n", &frame.func[strlen("__ecereDestructor_")], (s = CopySystemPath(frame.file)), frame.line);
2881 ide.callStackView.Logf($"%s Function, %s:%d\n", frame.func, (s = CopySystemPath(frame.file)), frame.line);
2886 ide.callStackView.Logf("%3d ", frame.level);
2891 ide.callStackView.Logf($"inside %s, %s\n", frame.func, (s = CopySystemPath(frame.from)));
2895 ide.callStackView.Logf("%s\n", frame.func);
2897 ide.callStackView.Logf($"unknown source\n");
2901 DebuggerProtocolUnknown("Unknown stack content", item.name);
2904 if(activeFrameLevel == -1)
2906 activeFrameLevel = 0;
2907 activeFrame = stackFrames.first;
2909 ide.callStackView.Home();
2911 subTokens.RemoveAll();
2913 /*else if(!strcmp(item.name, "frame"))
2916 item.value = StripCurlies(item.value);
2917 ParseFrame(&frame, item.value);
2919 else if(!strcmp(item.name, "thread-ids"))
2921 ide.threadsView.Clear();
2922 item.value = StripCurlies(item.value);
2923 TokenizeList(item.value, ',', subTokens);
2924 for(i = subTokens.count - 1; ; i--)
2926 if(TokenizeListItem(subTokens[i], item))
2928 if(!strcmp(item.name, "thread-id"))
2931 StripQuotes(item.value, item.value);
2932 value = atoi(item.value);
2933 ide.threadsView.Logf("%3d \n", value);
2936 DebuggerProtocolUnknown("Unknown threads content", item.name);
2941 ide.threadsView.Home();
2943 subTokens.RemoveAll();
2944 //if(!strcmp(outTokens[2], "number-of-threads"))
2946 else if(!strcmp(item.name, "new-thread-id"))
2948 StripQuotes(item.value, item.value);
2949 activeThread = atoi(item.value);
2951 else if(!strcmp(item.name, "value"))
2953 StripQuotes(item.value, item.value);
2954 eval.result = CopyString(item.value);
2955 eval.active = false;
2957 else if(!strcmp(item.name, "addr"))
2959 for(i = 2; i < outTokens.count; i++)
2961 if(TokenizeListItem(outTokens[i], item))
2963 if(!strcmp(item.name, "total-bytes"))
2965 StripQuotes(item.value, item.value);
2966 eval.bytes = atoi(item.value);
2968 else if(!strcmp(item.name, "next-row"))
2970 StripQuotes(item.value, item.value);
2971 eval.nextBlockAddress = strtoul(item.value, null, 0);
2973 else if(!strcmp(item.name, "memory"))
2977 //StripQuotes(item.value, item.value);
2978 item.value = StripBrackets(item.value);
2979 // this should be treated as a list...
2980 item.value = StripCurlies(item.value);
2981 TokenizeList(item.value, ',', subTokens);
2982 for(j = 0; j < subTokens.count; j++)
2984 if(TokenizeListItem(subTokens[j], item))
2986 if(!strcmp(item.name, "data"))
2988 item.value = StripBrackets(item.value);
2989 StripQuotes2(item.value, item.value);
2990 eval.result = CopyString(item.value);
2991 eval.active = false;
2995 subTokens.RemoveAll();
3000 else if(!strcmp(item.name, "source-path"))
3004 DebuggerProtocolUnknown("Unknown command reply", item.name);
3007 else if(!strcmp(outTokens[0], "^running"))
3009 waitingForPID = true;
3010 setWaitingForPID = true;
3012 else if(!strcmp(outTokens[0], "^exit"))
3014 ChangeState(terminated);
3015 // ide.outputView.debugBox.Logf("Exit\n");
3016 // ide.Update(null);
3018 serialSemaphore.Release();
3020 else if(!strcmp(outTokens[0], "^error"))
3024 sentBreakInsert = false;
3027 printf("problem\n");
3029 bpItem = GdbDataBreakpoint { };
3032 if(outTokens.count > 1 && TokenizeListItem(outTokens[1], item))
3034 if(!strcmp(item.name, "msg"))
3036 StripQuotes(item.value, item.value);
3039 eval.active = false;
3041 if(strstr(item.value, "No symbol") && strstr(item.value, "in current context"))
3042 eval.error = symbolNotFound;
3043 else if(strstr(item.value, "Cannot access memory at address"))
3044 eval.error = memoryCantBeRead;
3046 eval.error = unknown;
3048 else if(!strcmp(item.value, "Previous frame inner to this frame (corrupt stack?)"))
3051 else if(!strncmp(item.value, "Cannot access memory at address", 31))
3054 else if(!strcmp(item.value, "Cannot find bounds of current function"))
3056 ChangeState(stopped);
3057 gdbHandle.Printf("-exec-continue\n");
3059 else if(!strcmp(item.value, "ptrace: No such process."))
3061 ChangeState(loaded);
3062 targetProcessId = 0;
3064 else if(!strcmp(item.value, "Function \\\"WinMain\\\" not defined."))
3067 else if(!strcmp(item.value, "You can't do that without a process to debug."))
3069 ChangeState(loaded);
3070 targetProcessId = 0;
3072 else if(strstr(item.value, "No such file or directory."))
3074 ChangeState(loaded);
3075 targetProcessId = 0;
3077 else if(strstr(item.value, "During startup program exited with code "))
3079 ChangeState(loaded);
3080 targetProcessId = 0;
3085 if(strlen(item.value) < MAX_F_STRING)
3088 ide.outputView.debugBox.Logf("GDB: %s\n", (s = CopyUnescapedString(item.value)));
3092 ide.outputView.debugBox.Logf("GDB: %s\n", item.value);
3098 DebuggerProtocolUnknown("Unknown error content", item.name);
3101 DebuggerProtocolUnknown("Unknown result-record", outTokens[0]);
3103 outTokens.RemoveAll();
3106 DebuggerProtocolUnknown("Unknown status-async-output", outTokens[0]);
3109 if(TokenizeList(output, ',', outTokens) && !strcmp(outTokens[0], "=thread-group-created")) //=thread-group-created,id="7611"
3111 else if(!strcmp(outTokens[0], "=thread-created")) //=thread-created,id="1",group-id="7611"
3113 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"
3116 DebuggerProtocolUnknown("Unknown notify-async-output", outTokens[0]);
3117 outTokens.RemoveAll();
3121 if(TokenizeList(output, ',', outTokens))
3123 if(!strcmp(outTokens[0],"*running"))
3125 waitingForPID = true;
3126 setWaitingForPID = true;
3128 else if(!strcmp(outTokens[0], "*stopped"))
3130 ChangeState(stopped);
3132 if(outTokens.count > 1 && TokenizeListItem(outTokens[1], item))
3134 if(!strcmp(item.name, "reason"))
3136 char * reason = item.value;
3137 StripQuotes(reason, reason);
3138 if(!strcmp(reason, "exited-normally") || !strcmp(reason, "exited") || !strcmp(reason, "exited-signalled"))
3141 if(outTokens.count > 2 && TokenizeListItem(outTokens[2], item2))
3143 StripQuotes(item2.value, item2.value);
3144 if(!strcmp(item2.name, "exit-code"))
3145 exitCode = item2.value;
3151 HandleExit(reason, exitCode);
3153 else if(!strcmp(reason, "breakpoint-hit"))
3157 printf("problem\n");
3159 stopItem = GdbDataStop { };
3161 for(i = 2; i < outTokens.count; i++)
3163 TokenizeListItem(outTokens[i], item);
3164 StripQuotes(item.value, item.value);
3165 if(!strcmp(item.name, "bkptno"))
3166 stopItem.bkptno = atoi(item.value);
3167 else if(!strcmp(item.name, "thread-id"))
3168 stopItem.threadid = atoi(item.value);
3169 else if(!strcmp(item.name, "frame"))
3171 item.value = StripCurlies(item.value);
3172 ParseFrame(stopItem.frame, item.value);
3175 DebuggerProtocolUnknown("Unknown breakpoint hit item name", item.name);
3180 else if(!strcmp(reason, "end-stepping-range"))
3184 printf("problem\n");
3186 stopItem = GdbDataStop { };
3188 for(i = 2; i < outTokens.count; i++)
3190 TokenizeListItem(outTokens[i], item);
3191 StripQuotes(item.value, item.value);
3192 if(!strcmp(item.name, "thread-id"))
3193 stopItem.threadid = atoi(item.value);
3194 else if(!strcmp(item.name, "frame"))
3196 item.value = StripCurlies(item.value);
3197 ParseFrame(stopItem.frame, item.value);
3199 else if(!strcmp(item.name, "reason"))
3201 else if(!strcmp(item.name, "bkptno"))
3204 DebuggerProtocolUnknown("Unknown end of stepping range item name", item.name);
3210 else if(!strcmp(reason, "function-finished"))
3214 printf("problem\n");
3216 stopItem = GdbDataStop { };
3217 stopItem.reason = CopyString(reason);
3219 for(i = 2; i < outTokens.count; i++)
3221 TokenizeListItem(outTokens[i], item);
3222 StripQuotes(item.value, item.value);
3223 if(!strcmp(item.name, "thread-id"))
3224 stopItem.threadid = atoi(item.value);
3225 else if(!strcmp(item.name, "frame"))
3227 item.value = StripCurlies(item.value);
3228 ParseFrame(stopItem.frame, item.value);
3230 else if(!strcmp(item.name, "gdb-result-var"))
3231 stopItem.gdbResultVar = CopyString(item.value);
3232 else if(!strcmp(item.name, "return-value"))
3233 stopItem.returnValue = CopyString(item.value);
3235 DebuggerProtocolUnknown("Unknown function finished item name", item.name);
3238 event = functionEnd;
3241 else if(!strcmp(reason, "signal-received"))
3245 printf("problem\n");
3247 stopItem = GdbDataStop { };
3248 stopItem.reason = CopyString(reason);
3250 for(i = 2; i < outTokens.count; i++)
3252 TokenizeListItem(outTokens[i], item);
3253 StripQuotes(item.value, item.value);
3254 if(!strcmp(item.name, "signal-name"))
3255 stopItem.name = CopyString(item.value);
3256 else if(!strcmp(item.name, "signal-meaning"))
3257 stopItem.meaning = CopyString(item.value);
3258 else if(!strcmp(item.name, "thread-id"))
3259 stopItem.threadid = atoi(item.value);
3260 else if(!strcmp(item.name, "frame"))
3262 item.value = StripCurlies(item.value);
3263 ParseFrame(stopItem.frame, item.value);
3266 DebuggerProtocolUnknown("Unknown signal reveived item name", item.name);
3268 if(!strcmp(stopItem.name, "SIGTRAP"))
3287 else if(!strcmp(reason, "watchpoint-trigger"))
3288 DebuggerProtocolUnknown("Reason watchpoint trigger not handled", "");
3289 else if(!strcmp(reason, "read-watchpoint-trigger"))
3290 DebuggerProtocolUnknown("Reason read watchpoint trigger not handled", "");
3291 else if(!strcmp(reason, "access-watchpoint-trigger"))
3292 DebuggerProtocolUnknown("Reason access watchpoint trigger not handled", "");
3293 else if(!strcmp(reason, "watchpoint-scope"))
3294 DebuggerProtocolUnknown("Reason watchpoint scope not handled", "");
3295 else if(!strcmp(reason, "location-reached"))
3296 DebuggerProtocolUnknown("Reason location reached not handled", "");
3298 DebuggerProtocolUnknown("Unknown reason", reason);
3305 DebuggerProtocolUnknown("Unknown exec-async-output", outTokens[0]);
3306 outTokens.RemoveAll();
3309 if(!strcmpi(output, "(gdb) "))
3313 char exeFile[MAX_LOCATION];
3314 int oldProcessID = targetProcessId;
3315 GetLastDirectory(targetFile, exeFile);
3319 targetProcessId = Process_GetChildExeProcessId(gdbProcessId, exeFile);
3320 if(targetProcessId || gdbHandle.Peek()) break;
3325 ChangeState(running);
3326 else if(!oldProcessID)
3328 ide.outputView.debugBox.Logf($"Debugger Error: No target process ID\n");
3329 // TO VERIFY: The rest of this block has not been thoroughly tested in this particular location
3330 gdbHandle.Printf("-gdb-exit\n");
3332 ChangeState(terminated); //loaded;
3337 for(bp : ide.workspace.breakpoints)
3338 bp.inserted = false;
3341 bp.inserted = false;
3343 bpRunToCursor.inserted = false;
3345 ide.outputView.debugBox.Logf($"Debugging stopped\n");
3346 ClearBreakDisplay();
3348 #if defined(__unix__)
3349 if(FileExists(progFifoPath)) //fileCreated)
3351 progThread.terminate = true;
3354 fifoFile.CloseInput();
3361 DeleteFile(progFifoPath);
3362 progFifoPath[0] = '\0';
3369 serialSemaphore.Release();
3372 DebuggerProtocolUnknown($"Unknown prompt", output);
3376 if(!strncmp(output, "&\"warning:", 10))
3379 content = strstr(output, "\"");
3380 StripQuotes(content, content);
3381 content = strstr(content, ":");
3387 ide.outputView.debugBox.LogRaw((s = CopyUnescapedString(content)));
3394 DebuggerProtocolUnknown($"Unknown output", output);
3396 if(!setWaitingForPID)
3397 waitingForPID = false;
3398 setWaitingForPID = false;
3406 void RunToCursorPrepare(char * absoluteFilePath, char * relativeFilePath, int lineNumber)
3410 //bpRunToCursor.Free();
3411 bpRunToCursor = Breakpoint { };
3414 bpRunToCursor = Breakpoint { };
3416 if(absoluteFilePath)
3417 bpRunToCursor.absoluteFilePath = CopyString(absoluteFilePath);
3418 if(relativeFilePath)
3419 bpRunToCursor.relativeFilePath = CopyString(relativeFilePath);
3420 bpRunToCursor.line = lineNumber;
3421 bpRunToCursor.type = runToCursor;
3422 bpRunToCursor.enabled = true;
3423 bpRunToCursor.condition = null;
3424 bpRunToCursor.ignore = 0;
3425 bpRunToCursor.level = -1;
3428 ExpressionType ::DebugEvalExpTypeError(char * result)
3434 case symbolNotFound:
3435 return symbolErrorExp;
3436 case memoryCantBeRead:
3437 return memoryErrorExp;
3439 return unknownErrorExp;
3442 char * ::EvaluateExpression(char * expression, ExpressionType * error)
3445 if(ide.projectView && ide.debugger.state == stopped)
3447 result = GdbEvaluateExpression(expression);
3448 *error = DebugEvalExpTypeError(result);
3453 *error = noDebuggerErrorExp;
3458 char * ::ReadMemory(uint address, int size, char format, ExpressionType * error)
3461 char * result = GdbReadMemoryString(address, size, format, 1, 1);
3462 if(!result || !strcmp(result, "N/A"))
3463 *error = memoryErrorExp;
3465 *error = DebugEvalExpTypeError(result);
3470 class GdbThread : Thread
3476 static char output[4096];
3477 Array<char> dynamicBuffer { minAllocSize = 4096 };
3478 DualPipe oldGdbHandle = gdbHandle;
3479 incref oldGdbHandle;
3482 while(debugger.state != terminated && gdbHandle && !gdbHandle.Eof())
3486 result = gdbHandle.Read(output, 1, sizeof(output));
3488 if(debugger.state == terminated || !gdbHandle || gdbHandle.Eof())
3495 for(c = 0; c<result; c++)
3497 if(output[c] == '\n')
3499 int pos = dynamicBuffer.size;
3500 dynamicBuffer.size += c - start;
3501 memcpy(&dynamicBuffer[pos], output + start, c - start);
3502 if(dynamicBuffer.count && dynamicBuffer[dynamicBuffer.count - 1] != '\r')
3503 // COMMENTED OUT DUE TO ISSUE #135, FIXED
3504 //if(dynamicBuffer.array[dynamicBuffer.count - 1] != '\r')
3505 dynamicBuffer.size++;
3506 dynamicBuffer[dynamicBuffer.count - 1] = '\0';
3508 // printf("%s\n", dynamicBuffer.array);
3510 debugger.GdbThreadMain(&dynamicBuffer[0]);
3511 dynamicBuffer.size = 0;
3517 int pos = dynamicBuffer.size;
3518 dynamicBuffer.size += c - start;
3519 memcpy(&dynamicBuffer[pos], output + start, c - start);
3525 printf("Got end of file from GDB!\n");
3529 delete dynamicBuffer;
3530 //if(oldGdbHandle == gdbHandle)
3531 debugger.GdbThreadExit();
3532 delete oldGdbHandle;
3538 #if defined(__unix__)
3543 #include <sys/types.h>
3548 class ProgramThread : Thread
3554 bool fileCreated = false;
3556 static char output[1000];
3559 /*if(!mkfifo(progFifoPath, mask))
3566 ide.outputView.debugBox.Logf($"err: Unable to create FIFO %s\n", progFifoPath);
3570 if(FileExists(progFifoPath)) //fileCreated)
3572 fifoFile = FileOpen(progFifoPath, read);
3576 ide.outputView.debugBox.Logf($"err: Unable to open FIFO %s for read\n", progFifoPath);
3585 fd = fileno(fifoFile.input);
3587 //fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
3591 while(!terminate && fifoFile && !fifoFile.Eof())
3594 struct timeval time;
3602 selectResult = select(fd + 1, &rs, null, null, &time);
3603 if(FD_ISSET(fd, &rs))
3605 int result = read(fd, output, sizeof(output)-1);
3606 if(!result || (result < 0 && errno != EAGAIN))
3610 output[result] = '\0';
3611 if(strcmp(output,"&\"warning: GDB: Failed to set controlling terminal: Invalid argument\\n\"\n"))
3614 ide.outputView.debugBox.Log(output);
3623 //fifoFile.CloseInput();
3626 ide.outputView.debugBox.Log("\n");
3630 if(FileExists(progFifoPath)) //fileCreated)
3632 DeleteFile(progFifoPath);
3633 progFifoPath[0] = '\0';
3641 class Argument : struct
3643 Argument prev, next;
3659 class Frame : struct
3668 property char * from { set { delete from; if(value) from = CopyUnescapedUnixPath(value); } }
3670 property char * file { set { delete file; if(value) file = CopyUnescapedUnixPath(value); } }
3671 char * absoluteFile;
3680 delete absoluteFile;
3681 args.Free(Argument::Free);
3690 class GdbDataStop : struct
3707 char * gdbResultVar;
3717 if(!strcmp(reason, "signal-received"))
3722 else if(!strcmp(reason, "function-finished"))
3724 delete gdbResultVar;
3729 if(frame) frame.Free();
3738 class GdbDataBreakpoint : struct
3747 property char * file { set { delete file; if(value) file = CopyUnescapedUnixPath(value); } }
3762 ~GdbDataBreakpoint()
3768 class Breakpoint : struct
3772 char * relativeFilePath;
3773 char * absoluteFilePath;
3782 BreakpointType type;
3785 GdbDataBreakpoint bp;
3787 char * LocationToString()
3789 char location[MAX_LOCATION+20];
3790 sprintf(location, "%s:%d", relativeFilePath, line);
3791 #if defined(__WIN32__)
3792 ChangeCh(location, '/', '\\');
3794 return CopyString(location);
3799 if(relativeFilePath && relativeFilePath[0])
3801 f.Printf(" * %d,%d,%d,%d,%s\n", enabled ? 1 : 0, ignore, level, line, relativeFilePath);
3803 f.Printf(" ~ %s\n", condition.expression);
3812 delete relativeFilePath;
3813 delete absoluteFilePath;
3823 class Watch : struct
3834 f.Printf(" ~ %s\n", expression);
3858 class DebugListItem : struct
3864 struct DebugEvaluationData
3869 uint nextBlockAddress;
3871 DebuggerEvaluationError error;
3874 class CodeLocation : struct
3877 char * absoluteFile;
3880 CodeLocation ::ParseCodeLocation(char * location)
3884 char * colon = null;
3886 char loc[MAX_LOCATION];
3887 strcpy(loc, location);
3888 for(temp = loc; temp = strstr(temp, ":"); temp++)
3896 int line = atoi(colon);
3899 CodeLocation codloc { line = line };
3900 codloc.file = CopyString(loc);
3901 codloc.absoluteFile = ide.workspace.GetAbsolutePathFromRelative(loc);
3913 delete absoluteFile;