7 #define GDB_DEBUG_CONSOLE
10 extern char * strrchr(char * s, char c);
22 #include <sys/time.h> // Required on Apple...
27 public char * StripQuotes2(char * string, char * output)
31 bool quoted = false, escaped = false;
33 for(c = 0; ch = string[c]; c++)
37 if(escaped || ch != '\"')
40 escaped = !escaped && ch == '\\';
55 static void strescpy(char * d, char * s)
108 static char * CopyUnescapedSystemPath(char * p)
110 char * d = new char[strlen(p) + 1];
112 #if defined(__WIN32__)
113 ChangeCh(d, '/', '\\');
118 static char * CopyUnescapedUnixPath(char * p)
120 char * d = new char[strlen(p) + 1];
122 #if defined(__WIN32__)
123 ChangeCh(d, '\\', '/');
128 static char * CopyUnescapedString(char * s)
130 char * d = new char[strlen(s) + 1];
135 // String Unescape Copy
137 // TOFIX: THIS DOESN'T HANDLE NUMERIC ESCAPE CODES (OCTAL/HEXADECIMAL...)?
138 // Seems very similar to ReadString in pass15.ec (which also misses numeric escape codes :) )
140 static void struscpy(char * d, char * s)
192 static char * StripBrackets(char * string)
194 int length = strlen(string);
195 if(length > 1 && *string == '[' && string[length - 1] == ']')
198 string[length - 1] = '\0';
205 static char * StripCurlies(char * string)
207 int length = strlen(string);
208 if(length > 1 && *string == '{' && string[length - 1] == '}')
211 string[length - 1] = '\0';
218 static int StringGetInt(char * string, int start)
221 int i, len = strlen(string);
223 for(i = start; i < len && i < start + 8; i++)
225 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')
226 strncat(number, &string[i], 1);
233 static int TokenizeList(char * string, const char seperator, Array<char *> tokens)
237 bool quoted = false, escaped = false;
238 char * start = string, ch;
240 for(; (ch = *string); string++)
247 if(escaped || ch != '\"')
248 escaped = !escaped && ch == '\\';
254 else if(ch == '{' || ch == '[' || ch == '(' || ch == '<')
256 else if(ch == '}' || ch == ']' || ch == ')' || ch == '>')
258 else if(ch == seperator && !level)
267 //tokens[count] = start;
268 //tokens[count++] = start;
275 static bool TokenizeListItem(char * string, DebugListItem item)
277 char * equal = strstr(string, "=");
291 static void DebuggerProtocolUnknown(char * message, char * gdbOutput)
293 #ifdef _DEBUG_GDB_PROTOCOL
294 ide.outputView.debugBox.Logf("Debugger Protocol Error: %s (%s)\n", message, gdbOutput);
298 // define GdbGetLineSize = 1638400;
299 define GdbGetLineSize = 5638400;
300 #if defined(__unix__)
301 char progFifoPath[MAX_LOCATION];
302 char progFifoDir[MAX_LOCATION];
305 enum DebuggerState { none, prompt, loaded, running, stopped, terminated };
306 enum DebuggerEvent { none, hit, breakEvent, signal, stepEnd, functionEnd, exit };
307 enum DebuggerAction { none, internal, restart, stop, selectFrame }; //, bpValidation
308 enum BreakpointType { none, internalMain, internalWinMain, internalModulesLoaded, user, runToCursor };
309 enum DebuggerEvaluationError { none, symbolNotFound, memoryCantBeRead, unknown };
311 FileDialog debuggerFileDialog { type = selectDir };
313 static DualPipe gdbHandle;
314 static DebugEvaluationData eval { };
316 static int targetProcessId;
318 static bool gdbReady;
322 Semaphore serialSemaphore { };
327 //bool breakpointsInserted;
329 bool sentBreakInsert;
330 bool ignoreBreakpoints;
331 bool userBreakOnInternBreak;
338 int activeFrameLevel;
349 DebuggerAction breakType;
350 //DebuggerCommand lastCommand; // THE COMPILER COMPILES STUFF THAT DOES NOT EXIST???
352 GdbDataStop stopItem;
353 GdbDataBreakpoint bpItem;
356 List<Breakpoint> sysBPs { };
357 Breakpoint bpRunToCursor;
363 CompilerConfig currentCompiler;
364 ProjectConfig prjConfig;
366 CodeEditor codeEditor;
368 GdbThread gdbThread { debugger = this };
371 delay = 0.0, userData = this;
375 bool monitor = false;
376 DebuggerEvent curEvent = event;
377 GdbDataStop stopItem = this.stopItem;
383 this.stopItem = null;
386 if(curEvent && curEvent != exit)
389 printf("No stop item\n");
398 Restart(currentCompiler, prjConfig);
407 GdbCommand(false, "-stack-select-frame %d", activeFrameLevel);
408 for(activeFrame = stackFrames.first; activeFrame; activeFrame = activeFrame.next)
409 if(activeFrame.level == activeFrameLevel)
415 // GdbCommand(false, "-break-info %d", bpItem.number);
425 activeThread = stopItem.threadid;
426 GdbCommand(false, "-thread-list-ids");
431 Breakpoint bp = null;
433 for(i : ide.workspace.breakpoints; i.bp && i.bp.number == stopItem.bkptno)
440 for(i : sysBPs; i.bp && i.bp.number == stopItem.bkptno)
446 if(bp && bp.type != user && stopItem && stopItem.frame)
448 // In case the user put a breakpoint where an internal breakpoint is, avoid the confusion...
449 for(i : ide.workspace.breakpoints)
451 if(i.bp && i.line == stopItem.frame.line && !fstrcmp(i.absoluteFilePath, stopItem.frame.absoluteFile))
458 if(!(!userBreakOnInternBreak &&
459 bp && (bp.type == internalMain || bp.type == internalWinMain || bp.type == internalModulesLoaded)))
461 hitThread = stopItem.threadid;
465 signalThread = stopItem.threadid;
477 activeThread = stopItem.threadid;
478 GdbCommand(false, "-thread-list-ids");
480 if(activeFrameLevel > 0)
481 GdbCommand(false, "-stack-select-frame %d", activeFrameLevel);
483 WatchesCodeEditorLinkInit();
493 ide.outputView.debugBox.Logf($"Signal received: %s - %s\n", stopItem.name, stopItem.meaning);
494 ide.outputView.debugBox.Logf(" %s:%d\n", (s = CopySystemPath(stopItem.frame.file)), stopItem.frame.line);
500 // Why was SelectFrame missing here?
501 SelectFrame(activeFrameLevel);
502 GoToStackFrameLine(activeFrameLevel, curEvent == signal || curEvent == stepEnd /*false*/);
505 if(curEvent == signal)
506 ide.outputView.Show();
507 if(curEvent == signal || curEvent == breakEvent)
509 if(curEvent == breakEvent)
510 ide.threadsView.Show();
511 ide.callStackView.Show();
513 ide.ShowCodeEditor();
514 if(curEvent == breakEvent)
515 ide.callStackView.Activate();
523 ignoreBreakpoints = false;
534 #ifdef GDB_DEBUG_CONSOLE
535 char lastGdbOutput[GdbGetLineSize];
537 #if defined(__unix__)
538 ProgramThread progThread { };
541 void ChangeState(DebuggerState value)
543 bool same = value == state;
544 // if(same) PrintLn("Debugger::ChangeState -- changing to same state");
546 if(!same && ide) ide.AdjustDebugMenus();
551 // Stop(); // Don't need to call Stop here, because ~ProjectView() will call it explicitly.
553 stackFrames.Free(Frame::Free);
563 waitingForPID = false;
568 sentBreakInsert = false;
569 ignoreBreakpoints = false;
570 userBreakOnInternBreak = false;
573 activeFrameLevel = 0;
590 bpRunToCursor = null;
593 delete currentCompiler;
597 /*GdbThread gdbThread
603 ideProcessId = Process_GetCurrentProcessId();
605 sysBPs.Add(Breakpoint { type = internalMain, enabled = true, level = -1 });
606 #if defined(__WIN32__)
607 sysBPs.Add(Breakpoint { type = internalWinMain, enabled = true, level = -1 });
609 sysBPs.Add(Breakpoint { type = internalModulesLoaded, enabled = true, level = -1 });
622 property bool isActive { get { return state == running || state == stopped; } }
623 property bool isPrepared { get { return state == loaded || state == running || state == stopped; } }
627 GdbExecContinue(true);
635 GdbDebugBreak(false);
647 GdbDebugBreak(false);
658 void Restart(CompilerConfig compiler, ProjectConfig config)
666 GdbDebugBreak(false);
673 if(!GdbInit(compiler, config))
681 bool GoToCodeLine(char * location)
684 codloc = CodeLocation::ParseCodeLocation(location);
687 CodeEditor editor = (CodeEditor)ide.OpenFile(codloc.absoluteFile, normal, true, null, no, normal);
690 EditBox editBox = editor.editBox;
691 editBox.GoToLineNum(codloc.line - 1);
692 editBox.GoToPosition(editBox.line, codloc.line - 1, 0);
699 bool GoToStackFrameLine(int stackLevel, bool askForLocation)
703 char filePath[MAX_LOCATION];
704 char sourceDir[MAX_LOCATION];
706 CodeEditor editor = null;
707 if(stackLevel == -1) // this (the two lines) is part of that fix that I would not put in for some time
709 for(frame = stackFrames.first; frame; frame = frame.next)
710 if(frame.level == stackLevel)
714 ide.callStackView.Show();
716 if(!frame.absoluteFile && frame.file)
717 frame.absoluteFile = ide.workspace.GetAbsolutePathFromRelative(frame.file);
718 if(!frame.absoluteFile && askForLocation && frame.file)
721 char title[MAX_LOCATION];
723 sprintf(title, $"Provide source file location for %s", (s = CopySystemPath(frame.file)));
725 if(SourceDirDialog(title, ide.workspace.projectDir, frame.file, sourceDir))
727 AddSourceDir(sourceDir);
728 frame.absoluteFile = ide.workspace.GetAbsolutePathFromRelative(frame.file);
731 if(frame.absoluteFile)
732 editor = (CodeEditor)ide.OpenFile(frame.absoluteFile, normal, true, null, no, normal);
734 if(editor && frame.line)
736 EditBox editBox = editor.editBox;
737 editBox.GoToLineNum(frame.line - 1);
738 editBox.GoToPosition(editBox.line, frame.line - 1, 0);
746 void SelectThread(int thread)
750 if(thread != activeThread)
752 activeFrameLevel = -1;
753 ide.callStackView.Clear();
754 GdbCommand(false, "-thread-select %d", thread);
756 // Why was SelectFrame missing here?
757 SelectFrame(activeFrameLevel);
758 GoToStackFrameLine(activeFrameLevel, true);
759 WatchesCodeEditorLinkRelease();
760 WatchesCodeEditorLinkInit();
764 ide.callStackView.Show();
768 void SelectFrame(int frame)
772 if(frame != activeFrameLevel || !codeEditor || !codeEditor.visible)
774 activeFrameLevel = frame; // there is no active frame number in the gdb reply
775 GdbCommand(false, "-stack-select-frame %d", activeFrameLevel);
776 for(activeFrame = stackFrames.first; activeFrame; activeFrame = activeFrame.next)
777 if(activeFrame.level == activeFrameLevel)
780 WatchesCodeEditorLinkRelease();
781 WatchesCodeEditorLinkInit();
788 void HandleExit(char * reason, char * code)
790 bool returnedExitCode = false;
791 char verboseExitCode[128];
793 ChangeState(loaded); // this state change seems to be superfluous, might be in case of gdb crash
797 sprintf(verboseExitCode, $" with exit code %s", code);
799 verboseExitCode[0] = '\0';
803 // ClearBreakDisplay();
807 for(wh : ide.workspace.watches)
809 if(wh.type) FreeType(wh.type);
812 ide.watchesView.UpdateWatch(wh);
816 #if defined(__unix__)
817 progThread.terminate = true;
820 fifoFile.CloseInput();
829 char program[MAX_LOCATION];
830 GetSystemPathBuffer(program, targetFile);
832 ide.outputView.debugBox.Logf($"The program %s has exited%s.\n", program, verboseExitCode);
833 else if(!strcmp(reason, "exited-normally"))
834 ide.outputView.debugBox.Logf($"The program %s has exited normally%s.\n", program, verboseExitCode);
835 else if(!strcmp(reason, "exited"))
836 ide.outputView.debugBox.Logf($"The program %s has exited%s.\n", program, verboseExitCode);
837 else if(!strcmp(reason, "exited-signalled"))
838 ide.outputView.debugBox.Logf($"The program %s has exited with a signal%s.\n", program, verboseExitCode);
840 ide.outputView.debugBox.Logf($"The program %s has exited (gdb provided an unknown reason)%s.\n", program, verboseExitCode);
845 void Start(CompilerConfig compiler, ProjectConfig config)
847 ide.outputView.debugBox.Clear();
852 if(!GdbInit(compiler, config))
860 void StepInto(CompilerConfig compiler, ProjectConfig config)
866 if(!GdbInit(compiler, config))
869 ide.outputView.ShowClearSelectTab(debug);
870 ide.outputView.debugBox.Logf($"Starting debug mode\n");
871 userBreakOnInternBreak = true;
880 void StepOver(CompilerConfig compiler, ProjectConfig config, bool ignoreBkpts)
886 if(!GdbInit(compiler, config))
889 ide.outputView.ShowClearSelectTab(debug);
890 ide.outputView.debugBox.Logf($"Starting debug mode\n");
891 ignoreBreakpoints = ignoreBkpts;
892 userBreakOnInternBreak = true;
896 ignoreBreakpoints = ignoreBkpts;
897 if(ignoreBreakpoints)
898 GdbBreakpointsDelete(true);
904 void StepOut(bool ignoreBkpts)
908 ignoreBreakpoints = ignoreBkpts;
909 if(ignoreBreakpoints)
910 GdbBreakpointsDelete(true);
915 void RunToCursor(CompilerConfig compiler, ProjectConfig config, char * absoluteFilePath, int lineNumber, bool ignoreBkpts)
917 char relativeFilePath[MAX_LOCATION];
918 DebuggerState oldState = state;
919 ignoreBreakpoints = ignoreBkpts;
920 if(!ide.projectView.GetRelativePath(absoluteFilePath, relativeFilePath))
921 strcpy(relativeFilePath, absoluteFilePath);
926 Start(compiler, config);
933 ide.outputView.ShowClearSelectTab(debug);
934 ide.outputView.debugBox.Logf($"Starting debug mode\n");
936 RunToCursorPrepare(absoluteFilePath, relativeFilePath, lineNumber);
937 sentBreakInsert = true;
938 GdbCommand(false, "-break-insert %s:%d", relativeFilePath, lineNumber);
939 bpRunToCursor.bp = bpItem;
941 bpRunToCursor.inserted = (bpRunToCursor.bp.number != 0);
942 ValidateBreakpoint(bpRunToCursor);
949 if(ignoreBreakpoints)
950 GdbBreakpointsDelete(false);
954 if(ignoreBreakpoints)
955 GdbBreakpointsDelete(false);
956 GdbExecContinue(true);
962 void GetCallStackCursorLine(bool * error, int * lineCursor, int * lineTopFrame)
964 if(activeFrameLevel == -1)
972 *error = signalOn && activeThread == signalThread;
973 *lineCursor = activeFrameLevel + 1;
974 *lineTopFrame = activeFrameLevel ? 1 : 0;
978 int GetMarginIconsLineNumbers(char * fileName, int lines[], bool enabled[], int max, bool * error, int * lineCursor, int * lineTopFrame)
980 char winFilePath[MAX_LOCATION];
981 char * absoluteFilePath = GetSlashPathBuffer(winFilePath, fileName);
983 Iterator<Breakpoint> it { ide.workspace.breakpoints };
984 while(it.Next() && count < max)
986 Breakpoint bp = it.data;
989 if(bp.absoluteFilePath && bp.absoluteFilePath[0] && !fstrcmp(bp.absoluteFilePath, absoluteFilePath))
991 lines[count] = bp.line;
992 enabled[count] = bp.enabled;
997 if(activeFrameLevel == -1)
1005 *error = signalOn && activeThread == signalThread;
1006 if(activeFrame && activeFrame.absoluteFile && !fstrcmp(absoluteFilePath, activeFrame.absoluteFile))
1007 *lineCursor = activeFrame.line;
1010 if(activeFrame && stopItem && stopItem.frame && activeFrame.level == stopItem.frame.level)
1012 else if(stopItem && stopItem.frame && stopItem.frame.absoluteFile && !fstrcmp(absoluteFilePath, stopItem.frame.absoluteFile))
1013 *lineTopFrame = stopItem.frame.line;
1017 if(*lineTopFrame == *lineCursor && *lineTopFrame)
1023 void ChangeWatch(DataRow row, char * expression)
1025 Watch wh = (Watch)row.tag;
1028 delete wh.expression;
1030 wh.expression = CopyString(expression);
1033 Iterator<Watch> it { ide.workspace.watches };
1035 ide.workspace.watches.Delete(it.pointer);
1042 ide.workspace.watches.Add(wh);
1044 wh.expression = CopyString(expression);
1046 ide.workspace.Save();
1047 //if(expression && state == stopped)
1052 void MoveIcons(char * fileName, int lineNumber, int move, bool start)
1054 char winFilePath[MAX_LOCATION];
1055 char * absoluteFilePath = GetSlashPathBuffer(winFilePath, fileName);
1058 for(bpLink = ide.workspace.breakpoints.first; bpLink; bpLink = next)
1060 Breakpoint bp = (Breakpoint)bpLink.data;
1063 if(bp.type == user && bp.absoluteFilePath && !fstrcmp(bp.absoluteFilePath, absoluteFilePath))
1065 if(bp.line > lineNumber || (bp.line == lineNumber && start))
1067 if(move < 0 && (bp.line < lineNumber - move))
1068 ide.workspace.RemoveBreakpoint(bp);
1072 ide.breakpointsView.UpdateBreakpoint(bp.row);
1073 ide.workspace.Save();
1079 // moving code cursors is futile, on next step, stop, hit, cursors will be offset anyways
1082 bool SourceDirDialog(char * title, char * startDir, char * test, char * sourceDir)
1086 String srcDir = null;
1088 debuggerFileDialog.text = title;
1089 debuggerFileDialog.currentDirectory = startDir;
1090 debuggerFileDialog.master = ide;
1092 while(debuggerFileDialog.Modal())
1094 strcpy(sourceDir, debuggerFileDialog.filePath);
1095 if(!fstrcmp(ide.workspace.projectDir, sourceDir) &&
1096 MessageBox { type = yesNo, master = ide,
1097 contents = $"This is the project directory.\nWould you like to try again?",
1098 text = $"Invalid Source Directory" }.Modal() == no)
1102 for(dir : ide.workspace.sourceDirs)
1104 if(!fstrcmp(dir, sourceDir))
1112 MessageBox { type = yesNo, master = ide,
1113 contents = $"This source directory is already specified.\nWould you like to try again?",
1114 text = $"Invalid Source Directory" }.Modal() == no)
1120 char file[MAX_LOCATION];
1121 strcpy(file, sourceDir);
1122 PathCat(file, test);
1123 result = FileExists(file);
1125 MessageBox { type = yesNo, master = ide,
1126 contents = $"Unable to locate source file.\nWould you like to try again?",
1127 text = $"Invalid Source Directory" }.Modal() == no)
1141 void AddSourceDir(char * sourceDir)
1143 ide.workspace.sourceDirs.Add(CopyString(sourceDir));
1144 ide.workspace.Save();
1148 DebuggerState oldState = state;
1153 GdbDebugBreak(true);
1156 GdbCommand(false, "-environment-directory \"%s\"", sourceDir);
1159 if(oldState == running)
1160 GdbExecContinue(false);
1164 void ToggleBreakpoint(char * fileName, int lineNumber, Project prj)
1166 char winFilePath[MAX_LOCATION];
1167 char * absoluteFilePath = GetSlashPathBuffer(winFilePath, fileName);
1168 char absolutePath[MAX_LOCATION];
1169 char relativePath[MAX_LOCATION];
1170 char sourceDir[MAX_LOCATION];
1171 Breakpoint bp = null;
1173 strcpy(absolutePath, absoluteFilePath);
1174 for(i : ide.workspace.breakpoints; i.type == user && i.absoluteFilePath && !fstrcmp(i.absoluteFilePath, absolutePath) && i.line == lineNumber)
1183 ide.workspace.RemoveBreakpoint(bp);
1191 // FIXED: This is how it should have been... Source locations are only for files not in project
1192 // if(IsPathInsideOf(absolutePath, ide.workspace.projectDir))
1193 // MakePathRelative(absolutePath, ide.workspace.projectDir, relativePath);
1194 bool result = false;
1196 result = prj.GetRelativePath(absolutePath, relativePath);
1198 ide.projectView.GetRelativePath(absolutePath, relativePath);
1199 //if(ide.projectView.GetRelativePath(absolutePath, relativePath));
1203 char title[MAX_LOCATION];
1204 char directory[MAX_LOCATION];
1205 StripLastDirectory(absolutePath, directory);
1206 sprintf(title, $"Provide source files location directory for %s", absolutePath);
1209 String srcDir = null;
1210 for(dir : ide.workspace.sourceDirs)
1212 if(IsPathInsideOf(absolutePath, dir))
1214 MakePathRelative(absoluteFilePath, dir, relativePath);
1222 if(SourceDirDialog(title, directory, null, sourceDir))
1224 if(IsPathInsideOf(absolutePath, sourceDir))
1226 AddSourceDir(sourceDir);
1227 MakePathRelative(absoluteFilePath, sourceDir, relativePath);
1230 else if(MessageBox { type = yesNo, master = ide,
1231 contents = $"You must provide a valid source directory in order to place a breakpoint in this file.\nWould you like to try again?",
1232 text = $"Invalid Source Directory" }.Modal() == no)
1235 else if(MessageBox { type = yesNo, master = ide,
1236 contents = $"You must provide a source directory in order to place a breakpoint in this file.\nWould you like to try again?",
1237 text = $"No Source Directory Provided" }.Modal() == no)
1241 ide.workspace.bpCount++;
1242 bp = { line = lineNumber, type = user, enabled = true, level = -1 };
1243 ide.workspace.breakpoints.Add(bp);
1244 bp.absoluteFilePath = CopyString(absolutePath);
1245 bp.relativeFilePath = CopyString(relativePath);
1246 ide.breakpointsView.AddBreakpoint(bp);
1251 DebuggerState oldState = state;
1256 GdbDebugBreak(true);
1261 sentBreakInsert = true;
1262 GdbCommand(false, "-break-insert %s:%d", bp.relativeFilePath, bp.line);
1265 bp.inserted = (bp.bp && bp.bp.number != 0);
1266 ValidateBreakpoint(bp);
1270 if(oldState == running)
1271 GdbExecContinue(false);
1274 ide.workspace.Save();
1277 void UpdateRemovedBreakpoint(Breakpoint bp)
1279 if(targeted && bp.inserted)
1281 DebuggerState oldState = state;
1286 GdbDebugBreak(true);
1290 GdbCommand(false, "-break-delete %d", bp.bp.number);
1293 if(oldState == running)
1294 GdbExecContinue(false);
1300 void ParseFrame(Frame frame, char * string)
1303 Array<char *> frameTokens { minAllocSize = 50 };
1304 Array<char *> argsTokens { minAllocSize = 50 };
1305 Array<char *> argumentTokens { minAllocSize = 50 };
1306 DebugListItem item { };
1309 TokenizeList(string, ',', frameTokens);
1310 for(i = 0; i < frameTokens.count; i++)
1312 if(TokenizeListItem(frameTokens[i], item))
1314 StripQuotes(item.value, item.value);
1315 if(!strcmp(item.name, "level"))
1316 frame.level = atoi(item.value);
1317 else if(!strcmp(item.name, "addr"))
1318 frame.addr = CopyString(item.value);
1319 else if(!strcmp(item.name, "func"))
1320 frame.func = CopyString(item.value);
1321 else if(!strcmp(item.name, "args"))
1323 if(!strcmp(item.value, "[]"))
1324 frame.argsCount = 0;
1327 item.value = StripBrackets(item.value);
1328 TokenizeList(item.value, ',', argsTokens);
1329 for(j = 0; j < argsTokens.count; j++)
1331 argsTokens[j] = StripCurlies(argsTokens[j]);
1332 TokenizeList(argsTokens[j], ',', argumentTokens);
1333 for(k = 0; k < argumentTokens.count; k++)
1336 frame.args.Add(arg);
1337 if(TokenizeListItem(argumentTokens[k], item))
1339 if(!strcmp(item.name, "name"))
1341 StripQuotes(item.value, item.value);
1342 arg.name = CopyString(item.value);
1344 else if(!strcmp(item.name, "value"))
1346 StripQuotes(item.value, item.value);
1347 arg.value = CopyString(item.value);
1350 DebuggerProtocolUnknown("Unknown frame args item name", item.name);
1353 DebuggerProtocolUnknown("Bad frame args item", "");
1355 argumentTokens.RemoveAll();
1357 frame.argsCount = argsTokens.count;
1358 argsTokens.RemoveAll();
1361 else if(!strcmp(item.name, "from"))
1362 frame.from = item.value;
1363 else if(!strcmp(item.name, "file"))
1365 frame.file = item.value;
1366 frame.absoluteFile = ide.workspace.GetAbsolutePathFromRelative(frame.file);
1368 else if(!strcmp(item.name, "line"))
1369 frame.line = atoi(item.value);
1370 else if(!strcmp(item.name, "fullname"))
1372 // New GDB is giving us a full name... Any reason why we coudln't figure it out ourselves?
1375 DebuggerProtocolUnknown("Unknown frame member name", item.name);
1378 DebuggerProtocolUnknown("Bad frame", "");
1383 delete argumentTokens;
1387 void ShowDebuggerViews()
1389 ide.outputView.Show();
1390 ide.outputView.SelectTab(debug);
1391 ide.threadsView.Show();
1392 ide.callStackView.Show();
1393 ide.watchesView.Show();
1397 void HideDebuggerViews()
1399 ide.RepositionWindows(true);
1402 void ::GdbCommand(bool focus, char * format, ...)
1406 // TODO: Improve this limit
1407 static char string[MAX_F_STRING*3];
1410 va_start(args, format);
1411 vsprintf(string, format, args);
1415 ide.debugger.serialSemaphore.TryWait();
1418 #ifdef GDB_DEBUG_CONSOLE
1419 Log(string); Log("\n");
1421 #ifdef GDB_DEBUG_OUTPUT
1422 ide.outputView.gdbBox.Logf("cmd: %s\n", string);
1424 #ifdef GDB_DEBUG_GUI
1426 ide.gdbDialog.AddCommand(string);
1428 strcat(string,"\n");
1429 gdbHandle.Puts(string);
1432 Process_ShowWindows(targetProcessId);
1435 ide.debugger.serialSemaphore.Wait();
1440 bool ValidateBreakpoint(Breakpoint bp)
1444 if(bp.bp.line != bp.line)
1449 ide.outputView.debugBox.Logf("WOULD HAVE -- Invalid breakpoint disabled: %s:%d\n", bp.relativeFilePath, bp.line);
1453 //GdbCommand(false, "-break-delete %d", bp.bp.number);
1454 //bp.inserted = false;
1456 //bp.enabled = false;
1461 ide.outputView.debugBox.Logf("Debugger Error: ValidateBreakpoint error\n");
1462 bp.line = bp.bp.line;
1469 static void GdbInsertInternalBreakpoint()
1473 //if(!breakpointsInserted)
1475 DirExpression objDir = ide.project.GetObjDir(currentCompiler, prjConfig);
1480 if(bp.type == internalMain)
1482 sentBreakInsert = true;
1483 GdbCommand(false, "-break-insert main");
1486 bp.inserted = (bp.bp && bp.bp.number != 0);
1488 #if defined(__WIN32__)
1489 else if(bp.type == internalWinMain)
1491 sentBreakInsert = true;
1492 GdbCommand(false, "-break-insert WinMain");
1495 bp.inserted = (bp.bp && bp.bp.number != 0);
1498 else if(bp.type == internalModulesLoaded)
1500 char path[MAX_LOCATION];
1501 char name[MAX_LOCATION];
1502 char fixedModuleName[MAX_FILENAME];
1505 bool moduleLoadBlock = false;
1507 ReplaceSpaces(fixedModuleName, ide.project.moduleName);
1508 sprintf(name, "%s.main.ec", fixedModuleName);
1509 strcpy(path, ide.workspace.projectDir);
1510 PathCatSlash(path, objDir.dir);
1511 PathCatSlash(path, name);
1512 f = FileOpen(path, read);
1515 for(lineNumber = 1; !f.Eof(); lineNumber++)
1517 if(f.GetLine(line, sizeof(line) - 1))
1519 bool moduleLoadLine;
1520 TrimLSpaces(line, line);
1521 moduleLoadLine = !strncmp(line, "eModule_Load", strlen("eModule_Load"));
1522 if(!moduleLoadBlock && moduleLoadLine)
1523 moduleLoadBlock = true;
1524 else if(moduleLoadBlock && !moduleLoadLine && strlen(line) > 0)
1530 char relative[MAX_LOCATION];
1531 bp.absoluteFilePath = CopyString(path);
1532 MakePathRelative(path, ide.workspace.projectDir, relative);
1533 delete bp.relativeFilePath;
1534 bp.relativeFilePath = CopyString(relative);
1535 bp.line = lineNumber;
1536 sentBreakInsert = true;
1537 GdbCommand(false, "-break-insert %s:%d", bp.relativeFilePath, lineNumber);
1540 bp.inserted = (bp.bp && bp.bp.number != 0);
1541 ValidateBreakpoint(bp);
1554 void GdbBreakpointsInsert()
1558 //if(!breakpointsInserted)
1560 //if(!ignoreBreakpoints)
1561 //breakpointsInserted = true;
1562 for(bp : ide.workspace.breakpoints)
1564 if(!bp.inserted && bp.type == user)
1566 if(!ignoreBreakpoints && bp.enabled)
1568 sentBreakInsert = true;
1569 GdbCommand(false, "-break-insert %s:%d", bp.relativeFilePath, bp.line);
1572 bp.inserted = (bp.bp && bp.bp.number != 0);
1575 ValidateBreakpoint(bp);
1581 printf("problem\n");
1583 bp.bp = GdbDataBreakpoint { };
1587 if(bpRunToCursor && !bpRunToCursor.inserted)
1589 sentBreakInsert = true;
1590 GdbCommand(false, "-break-insert %s:%d", bpRunToCursor.relativeFilePath, bpRunToCursor.line);
1591 bpRunToCursor.bp = bpItem;
1593 bpRunToCursor.inserted = (bpRunToCursor.bp && bpRunToCursor.bp.number != 0);
1594 ValidateBreakpoint(bpRunToCursor);
1600 void GdbBreakpointsDelete(bool deleteRunToCursor)
1602 //breakpointsInserted = false;
1605 for(bp : ide.workspace.breakpoints)
1608 GdbCommand(false, "-break-delete %d", bp.bp.number);
1609 bp.inserted = false;
1611 //check here (reply form -break-delete, returns bpitem?)
1614 if(deleteRunToCursor && bpRunToCursor)
1616 GdbCommand(false, "-break-delete %d", bpRunToCursor.bp.number);
1617 bpRunToCursor.inserted = false;
1618 bpRunToCursor.bp = bpItem;
1619 //check here (reply form -break-delete, returns bpitem?)
1628 stackFrames.Free(Frame::Free);
1629 GdbCommand(false, "-stack-info-depth");
1631 GdbCommand(false, "-stack-info-depth 192");
1632 if(frameCount && frameCount <= 192)
1633 GdbCommand(false, "-stack-list-frames 0 191");
1636 GdbCommand(false, "-stack-list-frames 0 95");
1637 GdbCommand(false, "-stack-list-frames %d %d", Max(frameCount - 96, 96), frameCount - 1);
1639 GdbCommand(false, "");
1646 char escaped[MAX_LOCATION];
1647 strescpy(escaped, targetFile);
1648 GdbCommand(false, "file \"%s\"", escaped); //GDB/MI Missing Implementation -symbol-file, -target-attach
1653 for(prj : ide.workspace.projects)
1655 if(prj == ide.workspace.projects.firstIterator.data)
1658 //PrintLn("THIS: ", (String)prj.topNode.path);
1659 GdbCommand(false, "-environment-directory \"%s\"", prj.topNode.path);
1660 //GdbCommand(false, ""); // why this empty GDB command
1663 for(dir : ide.workspace.sourceDirs)
1665 GdbCommand(false, "-environment-directory \"%s\"", dir);
1666 //GdbCommand(false, ""); // why this empty GDB command
1668 GdbInsertInternalBreakpoint();
1674 void GdbTargetRelease()
1678 GdbBreakpointsDelete(true);
1679 GdbCommand(false, "file"); //GDB/MI Missing Implementation -target-detach
1685 void GdbDebugBreak(bool internal)
1690 breakType = DebuggerAction::internal;
1692 if(ide) ide.Update(null);
1694 if(Process_Break(targetProcessId)) //GdbCommand(false, "-exec-interrupt");
1695 serialSemaphore.Wait();
1698 ChangeState(loaded);
1699 targetProcessId = 0;
1704 ide.outputView.debugBox.Logf("Debugger Error: GdbDebugBreak with not target id should never happen\n");
1711 ShowDebuggerViews();
1712 GdbCommand(true, "-exec-run");
1715 void GdbExecContinue(bool focus)
1718 GdbCommand(focus, "-exec-continue");
1724 GdbCommand(true, "-exec-next");
1730 GdbCommand(true, "-exec-step");
1733 void GdbExecFinish()
1736 GdbCommand(true, "-exec-finish");
1739 void GdbExecCommon()
1741 ClearBreakDisplay();
1742 GdbBreakpointsInsert();
1745 #ifdef GDB_DEBUG_GUI
1746 void SendGDBCommand(char * command)
1748 DebuggerState oldState = state;
1753 GdbDebugBreak(true);
1756 GdbCommand(false, command);
1759 if(oldState == running)
1760 GdbExecContinue(false);
1764 void ClearBreakDisplay()
1767 activeFrameLevel = -1;
1778 stackFrames.Free(Frame::Free);
1779 WatchesCodeEditorLinkRelease();
1780 ide.callStackView.Clear();
1781 ide.threadsView.Clear();
1788 GdbCommand(false, "-interpreter-exec console \"kill\""); // should use -exec-abort -- GDB/MI implementation incomplete
1792 bool GdbInit(CompilerConfig compiler, ProjectConfig config)
1795 char oldDirectory[MAX_LOCATION];
1796 char tempPath[MAX_LOCATION];
1797 char command[MAX_LOCATION];
1798 Project project = ide.project;
1799 DirExpression targetDirExp = project.GetTargetDir(compiler, config);
1800 PathBackup pathBackup { };
1802 if(currentCompiler != compiler)
1804 delete currentCompiler;
1805 currentCompiler = compiler;
1806 incref currentCompiler;
1810 ChangeState(loaded);
1812 sentBreakInsert = false;
1816 //breakpointsInserted = false;
1818 ide.outputView.ShowClearSelectTab(debug);
1819 ide.outputView.debugBox.Logf($"Starting debug mode\n");
1821 #ifdef GDB_DEBUG_CONSOLE
1822 Log("Starting GDB"); Log("\n");
1824 #ifdef GDB_DEBUG_OUTPUT
1825 ide.outputView.gdbBox.Logf("run: Starting GDB\n");
1828 strcpy(tempPath, ide.workspace.projectDir);
1829 PathCatSlash(tempPath, targetDirExp.dir);
1831 targetDir = CopyString(tempPath);
1832 project.CatTargetFileName(tempPath, compiler, config);
1834 targetFile = CopyString(tempPath);
1836 GetWorkingDir(oldDirectory, MAX_LOCATION);
1837 if(ide.workspace.debugDir && ide.workspace.debugDir[0])
1839 char temp[MAX_LOCATION];
1840 strcpy(temp, ide.workspace.projectDir);
1841 PathCatSlash(temp, ide.workspace.debugDir);
1842 ChangeWorkingDir(temp);
1845 ChangeWorkingDir(ide.workspace.projectDir);
1847 ide.SetPath(true, compiler, config);
1849 // TODO: This pollutes the environment, but at least it works
1850 // It shouldn't really affect the IDE as the PATH gets restored and other variables set for testing will unlikely cause problems
1851 // What is the proper solution for this? DualPipeOpenEnv?
1852 // gdb set environment commands don't seem to take effect
1853 for(e : ide.workspace.environmentVars)
1855 SetEnvironment(e.name, e.string);
1858 sprintf(command, "gdb -n -silent --interpreter=mi2"); //-async //\"%s\"
1860 gdbHandle = DualPipeOpen(PipeOpenMode { output = 1, error = 2, input = 1 }, command);
1863 ide.outputView.debugBox.Logf($"Debugger Fatal Error: Couldn't start GDB\n");
1871 gdbProcessId = gdbHandle.GetProcessID();
1874 ide.outputView.debugBox.Logf($"Debugger Fatal Error: Couldn't get GDB process ID\n");
1880 serialSemaphore.Wait();
1885 //ChangeState(terminated);
1891 #if defined(__unix__)
1893 CreateTemporaryDir(progFifoDir, "ecereide");
1894 strcpy(progFifoPath, progFifoDir);
1895 PathCat(progFifoPath, "ideprogfifo");
1896 if(!mkfifo(progFifoPath, 0600))
1898 //fileCreated = true;
1903 ide.outputView.debugBox.Logf(createFIFOMsg, progFifoPath);
1908 progThread.terminate = false;
1909 progThread.Create();
1912 #if defined(__WIN32__)
1913 GdbCommand(false, "-gdb-set new-console on");
1916 GdbCommand(false, "-gdb-set verbose off");
1917 //GdbCommand(false, "-gdb-set exec-done-display on");
1918 GdbCommand(false, "-gdb-set step-mode off");
1919 GdbCommand(false, "-gdb-set unwindonsignal on");
1920 //GdbCommand(false, "-gdb-set shell on");
1921 GdbCommand(false, "set print elements 992");
1922 GdbCommand(false, "-gdb-set backtrace limit 100000");
1924 #if defined(__unix__)
1925 GdbCommand(false, "-inferior-tty-set %s", progFifoPath);
1928 GdbCommand(false, "-gdb-set args %s", ide.workspace.commandLineArgs ? ide.workspace.commandLineArgs : "");
1930 for(e : ide.workspace.environmentVars)
1932 GdbCommand(false, "set environment %s=%s", e.name, e.string);
1939 ChangeWorkingDir(oldDirectory);
1945 delete targetDirExp;
1951 if(gdbHandle && gdbProcessId)
1953 GdbCommand(false, "-gdb-exit");
1968 ChangeState(terminated); // this state change seems to be superfluous, is it safety for something?
1972 for(bp : ide.workspace.breakpoints)
1973 bp.inserted = false;
1975 bp.inserted = false;
1977 bpRunToCursor.inserted = false;
1979 ide.outputView.debugBox.Logf($"Debugging stopped\n");
1980 ClearBreakDisplay();
1983 #if defined(__unix__)
1984 if(FileExists(progFifoPath)) //fileCreated)
1986 progThread.terminate = true;
1989 fifoFile.CloseInput();
1995 DeleteFile(progFifoPath);
1996 progFifoPath[0] = '\0';
2002 void WatchesCodeEditorLinkInit()
2005 char tempPath[MAX_LOCATION];
2006 char path[MAX_LOCATION];
2008 //void MakeFilePathProjectRelative(char * path, char * relativePath)
2009 if(!ide.projectView.GetRelativePath(activeFrame.file, tempPath))
2010 strcpy(tempPath, activeFrame.file);
2012 strcpy(path, ide.workspace.projectDir);
2013 PathCat(path, tempPath);
2014 codeEditor = (CodeEditor)ide.OpenFile(path, Normal, false, null, no);
2017 for(srcDir : ide.workspace.sourceDirs)
2019 strcpy(path, srcDir);
2020 PathCat(path, tempPath);
2021 codeEditor = (CodeEditor)ide.OpenFile(path, Normal, false, null, no);
2022 if(codeEditor) break;
2027 if(activeFrame && !activeFrame.absoluteFile && activeFrame.file)
2028 activeFrame.absoluteFile = ide.workspace.GetAbsolutePathFromRelative(activeFrame.file);
2029 if(!activeFrame || !activeFrame.absoluteFile)
2032 codeEditor = (CodeEditor)ide.OpenFile(activeFrame.absoluteFile, normal, false, null, no, normal);
2035 codeEditor.inUseDebug = true;
2038 //watchesInit = true;
2041 void WatchesCodeEditorLinkRelease()
2047 codeEditor.inUseDebug = false;
2048 if(!codeEditor.visible)
2049 codeEditor.Destroy(0);
2055 bool ResolveWatch(Watch wh)
2057 bool result = false;
2070 char watchmsg[MAX_F_STRING];
2071 if(state == stopped && !codeEditor)
2072 wh.value = CopyString($"No source file found for selected frame");
2073 //if(codeEditor && state == stopped || state != stopped)
2076 Module backupPrivateModule;
2077 Context backupContext;
2078 Class backupThisClass;
2082 backupPrivateModule = GetPrivateModule();
2083 backupContext = GetCurrentContext();
2084 backupThisClass = GetThisClass();
2087 SetPrivateModule(codeEditor.privateModule);
2088 SetCurrentContext(codeEditor.globalContext);
2089 SetTopContext(codeEditor.globalContext);
2090 SetGlobalContext(codeEditor.globalContext);
2091 SetGlobalData(&codeEditor.globalData);
2094 exp = ParseExpressionString(wh.expression);
2096 if(exp && !parseError)
2098 if(GetPrivateModule())
2101 DebugFindCtxTree(codeEditor.ast, activeFrame.line, 0);
2102 ProcessExpressionType(exp);
2104 wh.type = exp.expType;
2107 DebugComputeExpression(exp);
2109 /*if(exp.hasAddress)
2111 char temp[MAX_F_STRING];
2112 sprintf(temp, "0x%x", exp.address);
2113 wh.address = CopyString(temp);
2114 // wh.address = CopyStringf("0x%x", exp.address);
2119 Type dataType = exp.expType;
2122 char temp[MAX_F_STRING];
2123 switch(dataType.kind)
2126 sprintf(temp, "%i", exp.val.c);
2129 sprintf(temp, "%i", exp.val.s);
2134 sprintf(temp, "%i", exp.val.i);
2137 sprintf(temp, "%i", exp.val.i64);
2140 sprintf(temp, "%i", exp.val.p);
2145 long v = (long)exp.val.f;
2146 sprintf(temp, "%i", v);
2151 long v = (long)exp.val.d;
2152 sprintf(temp, "%i", v);
2157 wh.intVal = CopyString(temp);
2158 switch(dataType.kind)
2161 sprintf(temp, "0x%x", exp.val.c);
2164 sprintf(temp, "0x%x", exp.val.s);
2168 sprintf(temp, "0x%x", exp.val.i);
2171 sprintf(temp, "0x%x", exp.val.i64);
2174 sprintf(temp, "0x%x", exp.val.i64);
2177 sprintf(temp, "0x%x", exp.val.p);
2182 long v = (long)exp.val.f;
2183 sprintf(temp, "0x%x", v);
2188 long v = (long)exp.val.d;
2189 sprintf(temp, "0x%x", v);
2194 wh.hexVal = CopyString(temp);
2195 switch(dataType.kind)
2198 sprintf(temp, "0o%o", exp.val.c);
2201 sprintf(temp, "0o%o", exp.val.s);
2205 sprintf(temp, "0o%o", exp.val.i);
2208 sprintf(temp, "0o%o", exp.val.i64);
2211 sprintf(temp, "0o%o", exp.val.i64);
2214 sprintf(temp, "0o%o", exp.val.p);
2219 long v = (long)exp.val.f;
2220 sprintf(temp, "0o%o", v);
2225 long v = (long)exp.val.d;
2226 sprintf(temp, "0o%o", v);
2231 wh.octVal = CopyString(temp);
2234 // WHATS THIS HERE ?
2235 if(exp.type == constantExp && exp.constant)
2236 wh.constant = CopyString(exp.constant);
2242 case symbolErrorExp:
2243 sprintf(watchmsg, $"Symbol \"%s\" not found", exp.identifier.string);
2245 case structMemberSymbolErrorExp:
2246 // todo get info as in next case (ExpClassMemberSymbolError)
2247 sprintf(watchmsg, $"Error: Struct member not found for \"%s\"", wh.expression);
2249 case classMemberSymbolErrorExp:
2252 Expression memberExp = exp.member.exp;
2253 Identifier memberID = exp.member.member;
2254 Type type = memberExp.expType;
2257 _class = (memberID && memberID.classSym) ? memberID.classSym.registered : ((type.kind == classType && type._class) ? type._class.registered : null);
2260 char string[256] = "";
2262 PrintType(type, string, false, true);
2263 classSym = FindClass(string);
2264 _class = classSym ? classSym.registered : null;
2267 sprintf(watchmsg, $"Member \"%s\" not found in class \"%s\"", memberID ? memberID.string : "", _class.name);
2269 sprintf(watchmsg, "Member \"%s\" not found in unregistered class? (Should never get this message)", memberID ? memberID.string : "");
2272 sprintf(watchmsg, "Member \"%s\" not found in no type? (Should never get this message)", memberID ? memberID.string : "");
2275 case memoryErrorExp:
2276 // Need to ensure when set to memoryErrorExp, constant is set
2277 sprintf(watchmsg, $"Memory can't be read at %s", /*(exp.type == constantExp) ? */exp.constant /*: null*/);
2279 case dereferenceErrorExp:
2280 sprintf(watchmsg, $"Dereference failure for \"%s\"", wh.expression);
2282 case unknownErrorExp:
2283 sprintf(watchmsg, $"Unknown error for \"%s\"", wh.expression);
2285 case noDebuggerErrorExp:
2286 sprintf(watchmsg, $"Debugger required for symbol evaluation in \"%s\"", wh.expression);
2288 case debugStateErrorExp:
2289 sprintf(watchmsg, $"Incorrect debugger state for symbol evaluation in \"%s\"", wh.expression);
2292 sprintf(watchmsg, $"Null type for \"%s\"", wh.expression);
2296 // Temporary Code for displaying Strings
2297 if((exp.expType && ((exp.expType.kind == pointerType ||
2298 exp.expType.kind == arrayType) && exp.expType.type.kind == charType)) ||
2299 (wh.type && wh.type.kind == classType && wh.type._class &&
2300 wh.type._class.registered && wh.type._class.registered.type == normalClass &&
2301 !strcmp(wh.type._class.registered.name, "String")))
2304 if(exp.expType.kind != arrayType || exp.hasAddress)
2310 //char temp[MAX_F_STRING * 32];
2312 ExpressionType evalError = dummyExp;
2313 /*if(exp.expType.kind == arrayType)
2314 sprintf(temp, "(char*)0x%x", exp.address);
2316 sprintf(temp, "(char*)%s", exp.constant);*/
2318 //evaluation = Debugger::EvaluateExpression(temp, &evalError);
2319 address = strtoul(exp.constant, null, 0);
2320 //printf("%x\n", address);
2321 sprintf(value, "0x%08x ", address);
2324 strcat(value, $"Null string");
2328 len = strlen(value);
2330 while(!string && size > 2)
2332 string = GdbReadMemory(address, size);
2335 if(string && string[0])
2338 if(UTF8Validate(string))
2343 for(c = 0; (ch = string[c]) && c<4096; c++)
2346 value[len++] = '\0';
2351 ISO8859_1toUTF8(string, value + len, 4096 - len - 30);
2352 strcat(value, ") (ISO8859-1)");
2359 strcat(value, $"Empty string");
2363 strcat(value, $"Couldn't read memory");
2365 wh.value = CopyString(value);
2368 else if(wh.type && wh.type.kind == classType && wh.type._class &&
2369 wh.type._class.registered && wh.type._class.registered.type == enumClass)
2371 uint64 value = strtoul(exp.constant, null, 0);
2372 Class enumClass = eSystem_FindClass(GetPrivateModule(), wh.type._class.registered.name);
2373 EnumClassData enumeration = (EnumClassData)enumClass.data;
2375 for(item = enumeration.values.first; item; item = item.next)
2376 if((int)item.data == value)
2379 wh.value = CopyString(item.name);
2381 wh.value = CopyString($"Invalid Enum Value");
2382 result = (bool)atoi(exp.constant);
2384 else if(wh.type && (wh.type.kind == charType || (wh.type.kind == classType && wh.type._class &&
2385 wh.type._class.registered && !strcmp(wh.type._class.registered.fullName, "ecere::com::unichar"))) )
2392 if(exp.constant[0] == '\'')
2394 if((int)((byte *)exp.constant)[1] > 127)
2397 value = UTF8GetChar(exp.constant + 1, &nb);
2398 if(nb < 2) value = exp.constant[1];
2399 signedValue = value;
2403 signedValue = exp.constant[1];
2405 // Precomp Syntax error with boot strap here:
2406 byte b = (byte)(char)signedValue;
2407 value = (unichar) b;
2413 if(wh.type.kind == charType && wh.type.isSigned)
2415 signedValue = (int)(char)strtol(exp.constant, null, 0);
2417 // Precomp Syntax error with boot strap here:
2418 byte b = (byte)(char)signedValue;
2419 value = (unichar) b;
2424 value = strtoul(exp.constant, null, 0);
2425 signedValue = (int)value;
2429 UTF32toUTF8Len(&value, 1, charString, 5);
2431 sprintf(string, "\'\\0' (0)");
2432 else if(value == '\t')
2433 sprintf(string, "\'\\t' (%d)", value);
2434 else if(value == '\n')
2435 sprintf(string, "\'\\n' (%d)", value);
2436 else if(value == '\r')
2437 sprintf(string, "\'\\r' (%d)", value);
2438 else if(wh.type.kind == charType && wh.type.isSigned)
2439 sprintf(string, "\'%s\' (%d)", charString, signedValue);
2440 else if(value > 256 || wh.type.kind != charType)
2442 if(value > 0x10FFFF || !GetCharCategory(value))
2443 sprintf(string, $"Invalid Unicode Keypoint (0x%08X)", value);
2445 sprintf(string, "\'%s\' (U+%04X)", charString, value);
2448 sprintf(string, "\'%s\' (%d)", charString, value);
2450 wh.value = CopyString(string);
2455 wh.value = CopyString(exp.constant);
2456 result = (bool)atoi(exp.constant);
2462 wh.value = PrintHexUInt(exp.address);
2463 result = (bool)exp.address;
2467 char tempString[256];
2468 if(exp.member.memberType == propertyMember)
2469 sprintf(watchmsg, $"Missing property evaluation support for \"%s\"", wh.expression);
2471 sprintf(watchmsg, $"Evaluation failed for \"%s\" of type \"%s\"", wh.expression,
2472 exp.type.OnGetString(tempString, null, null));
2478 sprintf(watchmsg, $"Invalid expression: \"%s\"", wh.expression);
2479 if(exp) FreeExpression(exp);
2482 SetPrivateModule(backupPrivateModule);
2483 SetCurrentContext(backupContext);
2484 SetTopContext(backupContext);
2485 SetGlobalContext(backupContext);
2486 SetThisClass(backupThisClass);
2489 // wh.value = CopyString("No source file found for selected frame");
2492 wh.value = CopyString(watchmsg);
2494 ide.watchesView.UpdateWatch(wh);
2498 void EvaluateWatches()
2500 for(wh : ide.workspace.watches)
2504 char * ::GdbEvaluateExpression(char * expression)
2508 GdbCommand(false, "-data-evaluate-expression \"%s\"", expression);
2510 ide.outputView.debugBox.Logf("Debugger Error: GdbEvaluateExpression\n");
2514 // to be removed... use GdbReadMemory that returns a byte array instead
2515 char * ::GdbReadMemoryString(uint address, int size, char format, int rows, int cols)
2521 printf("GdbReadMemoryString called with size = 0!\n");
2523 GdbCommand(false, "-data-read-memory 0x%08x %c, %d, %d, %d", address, format, size, rows, cols);
2525 ide.outputView.debugBox.Logf("Debugger Error: GdbReadMemoryString\n");
2529 byte * ::GdbReadMemory(uint address, int bytes)
2533 GdbCommand(false, "-data-read-memory 0x%08x %c, 1, 1, %d", address, 'u', bytes);
2536 printf("GdbReadMemory called with bytes = 0!\n");
2539 ide.outputView.debugBox.Logf("Debugger Error: GdbReadMemory\n");
2540 else if(eval.result && strcmp(eval.result, "N/A"))
2542 byte * result = new byte[bytes];
2543 byte * string = eval.result;
2547 result[c++] = (byte)strtol(string, &string, 10);
2563 void EventHit(GdbDataStop stopItem)
2565 bool conditionMet = true;
2566 Breakpoint bp = bpHit;
2568 if(!bp && bpRunToCursor)
2572 GdbCommand(false, "-break-delete %d", bp.bp.number);
2577 if(bp.type == user && bp.line != stopItem.frame.line)
2579 bp.line = stopItem.frame.line;
2580 ide.breakpointsView.UpdateBreakpoint(bp.row);
2581 ide.workspace.Save();
2587 case internalWinMain:
2588 GdbBreakpointsInsert();
2589 if(userBreakOnInternBreak)
2591 userBreakOnInternBreak = false;
2592 // Why was SelectFrame missing here?
2593 SelectFrame(activeFrameLevel);
2594 GoToStackFrameLine(activeFrameLevel, true);
2599 GdbExecContinue(false);
2601 case internalModulesLoaded:
2603 GdbBreakpointsInsert();
2604 GdbExecContinue(false);
2609 conditionMet = ResolveWatch(bp.condition);
2611 if((bp.level == -1 || bp.level == frameCount-1) && conditionMet)
2616 ignoreBreakpoints = false;
2617 // Why was SelectFrame missing here?
2618 SelectFrame(activeFrameLevel);
2619 GoToStackFrameLine(activeFrameLevel, true);
2622 if(bp.type == BreakpointType::runToCursor)
2624 delete bpRunToCursor;
2625 bpRunToCursor = null;
2631 GdbExecContinue(false);
2635 GdbExecContinue(false);
2636 ide.breakpointsView.UpdateBreakpoint(bp.row);
2641 ide.outputView.debugBox.Logf("Debugger Error: Breakpoint hit could not match breakpoint instance\n");
2644 void GdbThreadExit()
2646 if(state != terminated)
2648 ChangeState(terminated);
2649 targetProcessId = 0;
2650 ClearBreakDisplay();
2654 serialSemaphore.Release();
2659 ide.outputView.debugBox.Logf($"Debugger Fatal Error: GDB lost\n");
2660 ide.outputView.debugBox.Logf($"Debugging stopped\n");
2663 //ChangeState(terminated);
2667 void GdbThreadMain(char * output)
2670 Array<char *> outTokens { minAllocSize = 50 };
2671 Array<char *> subTokens { minAllocSize = 50 };
2672 DebugListItem item { };
2673 DebugListItem item2 { };
2674 bool setWaitingForPID = false;
2676 #if defined(GDB_DEBUG_CONSOLE) || defined(GDB_DEBUG_GUI)
2677 #ifdef GDB_DEBUG_CONSOLE
2678 Log(output); Log("\n");
2680 #ifdef GDB_DEBUG_OUTPUT
2682 int len = strlen(output);
2690 for(c = 0; c < len / 1024; c++)
2692 strncpy(tmp, start, 1024);
2693 ide.outputView.gdbBox.Logf("out: %s\n", tmp);
2696 ide.outputView.gdbBox.Logf("out: %s\n", start);
2700 ide.outputView.gdbBox.Logf("out: %s\n", output);
2704 #ifdef GDB_DEBUG_CONSOLE
2705 strcpy(lastGdbOutput, output);
2707 #ifdef GDB_DEBUG_GUI
2708 if(ide.gdbDialog) ide.gdbDialog.AddOutput(output);
2715 if(strstr(output, "No debugging symbols found") || strstr(output, "(no debugging symbols found)"))
2718 ide.outputView.debugBox.Logf($"Target doesn't contain debug information!\n");
2724 if(TokenizeList(output, ',', outTokens) && !strcmp(outTokens[0], "^done"))
2726 //if(outTokens.count == 1)
2731 ChangeState(loaded);
2732 targetProcessId = 0;
2733 if(outTokens.count > 1 && TokenizeListItem(outTokens[1], item))
2735 if(!strcmp(item.name, "reason"))
2737 char * reason = item.value;
2738 StripQuotes(reason, reason);
2739 if(!strcmp(reason, "exited-normally") || !strcmp(reason, "exited") || !strcmp(reason, "exited-signalled"))
2742 if(outTokens.count > 2 && TokenizeListItem(outTokens[2], item2))
2744 StripQuotes(item2.value, item2.value);
2745 if(!strcmp(item2.name, "exit-code"))
2746 exitCode = item2.value;
2752 HandleExit(reason, exitCode);
2756 DebuggerProtocolUnknown("Unknown kill reply", item.name);
2759 HandleExit(null, null);
2762 if(outTokens.count > 1 && TokenizeListItem(outTokens[1], item))
2764 if(!strcmp(item.name, "bkpt"))
2766 sentBreakInsert = false;
2769 printf("problem\n");
2771 bpItem = GdbDataBreakpoint { };
2772 item.value = StripCurlies(item.value);
2773 TokenizeList(item.value, ',', subTokens);
2774 for(i = 0; i < subTokens.count; i++)
2776 if(TokenizeListItem(subTokens[i], item))
2778 StripQuotes(item.value, item.value);
2779 if(!strcmp(item.name, "number"))
2780 bpItem.number = atoi(item.value);
2781 else if(!strcmp(item.name, "type"))
2782 bpItem.type = CopyString(item.value);
2783 else if(!strcmp(item.name, "disp"))
2784 bpItem.disp = CopyString(item.value);
2785 else if(!strcmp(item.name, "enabled"))
2786 bpItem.enabled = (!strcmpi(item.value, "y"));
2787 else if(!strcmp(item.name, "addr"))
2788 bpItem.addr = CopyString(item.value);
2789 else if(!strcmp(item.name, "func"))
2790 bpItem.func = CopyString(item.value);
2791 else if(!strcmp(item.name, "file"))
2792 bpItem.file = item.value;
2793 else if(!strcmp(item.name, "line"))
2794 bpItem.line = atoi(item.value);
2795 else if(!strcmp(item.name, "at"))
2796 bpItem.at = CopyString(item.value);
2797 else if(!strcmp(item.name, "times"))
2798 bpItem.times = atoi(item.value);
2801 //breakType = bpValidation;
2802 //app.SignalEvent();
2803 subTokens.RemoveAll();
2805 else if(!strcmp(item.name, "BreakpointTable"))
2806 ide.outputView.debugBox.Logf("Debugger Error: Command reply BreakpointTable not handled\n");
2807 else if(!strcmp(item.name, "depth"))
2809 StripQuotes(item.value, item.value);
2810 frameCount = atoi(item.value);
2812 stackFrames.Free(Frame::Free);
2814 else if(!strcmp(item.name, "stack"))
2817 if(stackFrames.count)
2818 ide.callStackView.Logf("...\n");
2821 item.value = StripBrackets(item.value);
2822 TokenizeList(item.value, ',', subTokens);
2823 for(i = 0; i < subTokens.count; i++)
2825 if(TokenizeListItem(subTokens[i], item))
2827 if(!strcmp(item.name, "frame"))
2830 stackFrames.Add(frame);
2831 item.value = StripCurlies(item.value);
2832 ParseFrame(frame, item.value);
2833 if(frame.file && frame.from)
2834 DebuggerProtocolUnknown("Unexpected frame file and from members present", "");
2838 if(activeFrameLevel == -1)
2840 if(ide.projectView.IsModuleInProject(frame.file));
2842 if(frame.level != 0)
2844 //stopItem.frame = frame;
2845 breakType = selectFrame;
2848 activeFrame = frame;
2849 activeFrameLevel = frame.level;
2852 ide.callStackView.Logf("%3d ", frame.level);
2853 if(!strncmp(frame.func, "__ecereMethod_", strlen("__ecereMethod_")))
2854 ide.callStackView.Logf($"%s Method, %s:%d\n", &frame.func[strlen("__ecereMethod_")], (s = CopySystemPath(frame.file)), frame.line);
2855 else if(!strncmp(frame.func, "__ecereProp_", strlen("__ecereProp_")))
2856 ide.callStackView.Logf($"%s Property, %s:%d\n", &frame.func[strlen("__ecereProp_")], (s = CopySystemPath(frame.file)), frame.line);
2857 else if(!strncmp(frame.func, "__ecereConstructor_", strlen("__ecereConstructor_")))
2858 ide.callStackView.Logf($"%s Constructor, %s:%d\n", &frame.func[strlen("__ecereConstructor_")], (s = CopySystemPath(frame.file)), frame.line);
2859 else if(!strncmp(frame.func, "__ecereDestructor_", strlen("__ecereDestructor_")))
2860 ide.callStackView.Logf($"%s Destructor, %s:%d\n", &frame.func[strlen("__ecereDestructor_")], (s = CopySystemPath(frame.file)), frame.line);
2862 ide.callStackView.Logf($"%s Function, %s:%d\n", frame.func, (s = CopySystemPath(frame.file)), frame.line);
2867 ide.callStackView.Logf("%3d ", frame.level);
2872 ide.callStackView.Logf($"inside %s, %s\n", frame.func, (s = CopySystemPath(frame.from)));
2876 ide.callStackView.Logf("%s\n", frame.func);
2878 ide.callStackView.Logf($"unknown source\n");
2882 DebuggerProtocolUnknown("Unknown stack content", item.name);
2885 if(activeFrameLevel == -1)
2887 activeFrameLevel = 0;
2888 activeFrame = stackFrames.first;
2890 ide.callStackView.Home();
2892 subTokens.RemoveAll();
2894 /*else if(!strcmp(item.name, "frame"))
2897 item.value = StripCurlies(item.value);
2898 ParseFrame(&frame, item.value);
2900 else if(!strcmp(item.name, "thread-ids"))
2902 ide.threadsView.Clear();
2903 item.value = StripCurlies(item.value);
2904 TokenizeList(item.value, ',', subTokens);
2905 for(i = subTokens.count - 1; ; i--)
2907 if(TokenizeListItem(subTokens[i], item))
2909 if(!strcmp(item.name, "thread-id"))
2912 StripQuotes(item.value, item.value);
2913 value = atoi(item.value);
2914 ide.threadsView.Logf("%3d \n", value);
2917 DebuggerProtocolUnknown("Unknown threads content", item.name);
2922 ide.threadsView.Home();
2924 subTokens.RemoveAll();
2925 //if(!strcmp(outTokens[2], "number-of-threads"))
2927 else if(!strcmp(item.name, "new-thread-id"))
2929 StripQuotes(item.value, item.value);
2930 activeThread = atoi(item.value);
2932 else if(!strcmp(item.name, "value"))
2934 StripQuotes(item.value, item.value);
2935 eval.result = CopyString(item.value);
2936 eval.active = false;
2938 else if(!strcmp(item.name, "addr"))
2940 for(i = 2; i < outTokens.count; i++)
2942 if(TokenizeListItem(outTokens[i], item))
2944 if(!strcmp(item.name, "total-bytes"))
2946 StripQuotes(item.value, item.value);
2947 eval.bytes = atoi(item.value);
2949 else if(!strcmp(item.name, "next-row"))
2951 StripQuotes(item.value, item.value);
2952 eval.nextBlockAddress = strtoul(item.value, null, 0);
2954 else if(!strcmp(item.name, "memory"))
2958 item.value = StripBrackets(item.value);
2959 // this should be treated as a list...
2960 item.value = StripCurlies(item.value);
2961 TokenizeList(item.value, ',', subTokens);
2962 for(j = 0; j < subTokens.count; j++)
2964 if(TokenizeListItem(subTokens[j], item))
2966 if(!strcmp(item.name, "data"))
2968 item.value = StripBrackets(item.value);
2969 StripQuotes2(item.value, item.value);
2970 eval.result = CopyString(item.value);
2971 eval.active = false;
2975 subTokens.RemoveAll();
2980 else if(!strcmp(item.name, "source-path"))
2984 DebuggerProtocolUnknown("Unknown command reply", item.name);
2987 else if(!strcmp(outTokens[0], "^running"))
2989 waitingForPID = true;
2990 setWaitingForPID = true;
2992 else if(!strcmp(outTokens[0], "^exit"))
2994 ChangeState(terminated);
2995 // ide.outputView.debugBox.Logf("Exit\n");
2996 // ide.Update(null);
2998 serialSemaphore.Release();
3000 else if(!strcmp(outTokens[0], "^error"))
3004 sentBreakInsert = false;
3007 printf("problem\n");
3009 bpItem = GdbDataBreakpoint { };
3012 if(outTokens.count > 1 && TokenizeListItem(outTokens[1], item))
3014 if(!strcmp(item.name, "msg"))
3016 StripQuotes(item.value, item.value);
3019 eval.active = false;
3021 if(strstr(item.value, "No symbol") && strstr(item.value, "in current context"))
3022 eval.error = symbolNotFound;
3023 else if(strstr(item.value, "Cannot access memory at address"))
3024 eval.error = memoryCantBeRead;
3026 eval.error = unknown;
3028 else if(!strcmp(item.value, "Previous frame inner to this frame (corrupt stack?)"))
3031 else if(!strncmp(item.value, "Cannot access memory at address", 31))
3034 else if(!strcmp(item.value, "Cannot find bounds of current function"))
3036 ChangeState(stopped);
3037 gdbHandle.Printf("-exec-continue\n");
3039 else if(!strcmp(item.value, "ptrace: No such process."))
3041 ChangeState(loaded);
3042 targetProcessId = 0;
3044 else if(!strcmp(item.value, "Function \\\"WinMain\\\" not defined."))
3047 else if(!strcmp(item.value, "You can't do that without a process to debug."))
3049 ChangeState(loaded);
3050 targetProcessId = 0;
3052 else if(strstr(item.value, "No such file or directory."))
3054 ChangeState(loaded);
3055 targetProcessId = 0;
3057 else if(strstr(item.value, "During startup program exited with code "))
3059 ChangeState(loaded);
3060 targetProcessId = 0;
3065 if(strlen(item.value) < MAX_F_STRING)
3068 ide.outputView.debugBox.Logf("GDB: %s\n", (s = CopyUnescapedString(item.value)));
3072 ide.outputView.debugBox.Logf("GDB: %s\n", item.value);
3078 DebuggerProtocolUnknown("Unknown error content", item.name);
3081 DebuggerProtocolUnknown("Unknown result-record", outTokens[0]);
3083 outTokens.RemoveAll();
3086 DebuggerProtocolUnknown("Unknown status-async-output", outTokens[0]);
3089 if(TokenizeList(output, ',', outTokens) && !strcmp(outTokens[0], "=thread-group-created")) //=thread-group-created,id="7611"
3091 else if(!strcmp(outTokens[0], "=thread-created")) //=thread-created,id="1",group-id="7611"
3093 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"
3096 DebuggerProtocolUnknown("Unknown notify-async-output", outTokens[0]);
3097 outTokens.RemoveAll();
3101 if(TokenizeList(output, ',', outTokens))
3103 if(!strcmp(outTokens[0],"*running"))
3105 waitingForPID = true;
3106 setWaitingForPID = true;
3108 else if(!strcmp(outTokens[0], "*stopped"))
3110 ChangeState(stopped);
3112 if(outTokens.count > 1 && TokenizeListItem(outTokens[1], item))
3114 if(!strcmp(item.name, "reason"))
3116 char * reason = item.value;
3117 StripQuotes(reason, reason);
3118 if(!strcmp(reason, "exited-normally") || !strcmp(reason, "exited") || !strcmp(reason, "exited-signalled"))
3121 if(outTokens.count > 2 && TokenizeListItem(outTokens[2], item2))
3123 StripQuotes(item2.value, item2.value);
3124 if(!strcmp(item2.name, "exit-code"))
3125 exitCode = item2.value;
3131 HandleExit(reason, exitCode);
3133 else if(!strcmp(reason, "breakpoint-hit"))
3137 printf("problem\n");
3139 stopItem = GdbDataStop { };
3141 for(i = 2; i < outTokens.count; i++)
3143 TokenizeListItem(outTokens[i], item);
3144 StripQuotes(item.value, item.value);
3145 if(!strcmp(item.name, "bkptno"))
3146 stopItem.bkptno = atoi(item.value);
3147 else if(!strcmp(item.name, "thread-id"))
3148 stopItem.threadid = atoi(item.value);
3149 else if(!strcmp(item.name, "frame"))
3151 item.value = StripCurlies(item.value);
3152 ParseFrame(stopItem.frame, item.value);
3155 DebuggerProtocolUnknown("Unknown breakpoint hit item name", item.name);
3160 else if(!strcmp(reason, "end-stepping-range"))
3164 printf("problem\n");
3166 stopItem = GdbDataStop { };
3168 for(i = 2; i < outTokens.count; i++)
3170 TokenizeListItem(outTokens[i], item);
3171 StripQuotes(item.value, item.value);
3172 if(!strcmp(item.name, "thread-id"))
3173 stopItem.threadid = atoi(item.value);
3174 else if(!strcmp(item.name, "frame"))
3176 item.value = StripCurlies(item.value);
3177 ParseFrame(stopItem.frame, item.value);
3179 else if(!strcmp(item.name, "reason"))
3181 else if(!strcmp(item.name, "bkptno"))
3184 DebuggerProtocolUnknown("Unknown end of stepping range item name", item.name);
3190 else if(!strcmp(reason, "function-finished"))
3194 printf("problem\n");
3196 stopItem = GdbDataStop { };
3197 stopItem.reason = CopyString(reason);
3199 for(i = 2; i < outTokens.count; i++)
3201 TokenizeListItem(outTokens[i], item);
3202 StripQuotes(item.value, item.value);
3203 if(!strcmp(item.name, "thread-id"))
3204 stopItem.threadid = atoi(item.value);
3205 else if(!strcmp(item.name, "frame"))
3207 item.value = StripCurlies(item.value);
3208 ParseFrame(stopItem.frame, item.value);
3210 else if(!strcmp(item.name, "gdb-result-var"))
3211 stopItem.gdbResultVar = CopyString(item.value);
3212 else if(!strcmp(item.name, "return-value"))
3213 stopItem.returnValue = CopyString(item.value);
3215 DebuggerProtocolUnknown("Unknown function finished item name", item.name);
3218 event = functionEnd;
3221 else if(!strcmp(reason, "signal-received"))
3225 printf("problem\n");
3227 stopItem = GdbDataStop { };
3228 stopItem.reason = CopyString(reason);
3230 for(i = 2; i < outTokens.count; i++)
3232 TokenizeListItem(outTokens[i], item);
3233 StripQuotes(item.value, item.value);
3234 if(!strcmp(item.name, "signal-name"))
3235 stopItem.name = CopyString(item.value);
3236 else if(!strcmp(item.name, "signal-meaning"))
3237 stopItem.meaning = CopyString(item.value);
3238 else if(!strcmp(item.name, "thread-id"))
3239 stopItem.threadid = atoi(item.value);
3240 else if(!strcmp(item.name, "frame"))
3242 item.value = StripCurlies(item.value);
3243 ParseFrame(stopItem.frame, item.value);
3246 DebuggerProtocolUnknown("Unknown signal reveived item name", item.name);
3248 if(!strcmp(stopItem.name, "SIGTRAP"))
3267 else if(!strcmp(reason, "watchpoint-trigger"))
3268 DebuggerProtocolUnknown("Reason watchpoint trigger not handled", "");
3269 else if(!strcmp(reason, "read-watchpoint-trigger"))
3270 DebuggerProtocolUnknown("Reason read watchpoint trigger not handled", "");
3271 else if(!strcmp(reason, "access-watchpoint-trigger"))
3272 DebuggerProtocolUnknown("Reason access watchpoint trigger not handled", "");
3273 else if(!strcmp(reason, "watchpoint-scope"))
3274 DebuggerProtocolUnknown("Reason watchpoint scope not handled", "");
3275 else if(!strcmp(reason, "location-reached"))
3276 DebuggerProtocolUnknown("Reason location reached not handled", "");
3278 DebuggerProtocolUnknown("Unknown reason", reason);
3285 DebuggerProtocolUnknown("Unknown exec-async-output", outTokens[0]);
3286 outTokens.RemoveAll();
3289 if(!strcmpi(output, "(gdb) "))
3293 char exeFile[MAX_LOCATION];
3294 int oldProcessID = targetProcessId;
3295 GetLastDirectory(targetFile, exeFile);
3299 targetProcessId = Process_GetChildExeProcessId(gdbProcessId, exeFile);
3300 if(targetProcessId || gdbHandle.Peek()) break;
3305 ChangeState(running);
3306 else if(!oldProcessID)
3308 ide.outputView.debugBox.Logf($"Debugger Error: No target process ID\n");
3309 // TO VERIFY: The rest of this block has not been thoroughly tested in this particular location
3310 gdbHandle.Printf("-gdb-exit\n");
3312 ChangeState(terminated); //loaded;
3317 for(bp : ide.workspace.breakpoints)
3318 bp.inserted = false;
3321 bp.inserted = false;
3323 bpRunToCursor.inserted = false;
3325 ide.outputView.debugBox.Logf($"Debugging stopped\n");
3326 ClearBreakDisplay();
3328 #if defined(__unix__)
3329 if(FileExists(progFifoPath)) //fileCreated)
3331 progThread.terminate = true;
3334 fifoFile.CloseInput();
3341 DeleteFile(progFifoPath);
3342 progFifoPath[0] = '\0';
3349 serialSemaphore.Release();
3352 DebuggerProtocolUnknown($"Unknown prompt", output);
3356 if(!strncmp(output, "&\"warning:", 10))
3359 content = strstr(output, "\"");
3360 StripQuotes(content, content);
3361 content = strstr(content, ":");
3367 ide.outputView.debugBox.LogRaw((s = CopyUnescapedString(content)));
3374 DebuggerProtocolUnknown($"Unknown output", output);
3376 if(!setWaitingForPID)
3377 waitingForPID = false;
3378 setWaitingForPID = false;
3386 void RunToCursorPrepare(char * absoluteFilePath, char * relativeFilePath, int lineNumber)
3390 //bpRunToCursor.Free();
3391 bpRunToCursor = Breakpoint { };
3394 bpRunToCursor = Breakpoint { };
3396 if(absoluteFilePath)
3397 bpRunToCursor.absoluteFilePath = CopyString(absoluteFilePath);
3398 if(relativeFilePath)
3399 bpRunToCursor.relativeFilePath = CopyString(relativeFilePath);
3400 bpRunToCursor.line = lineNumber;
3401 bpRunToCursor.type = runToCursor;
3402 bpRunToCursor.enabled = true;
3403 bpRunToCursor.condition = null;
3404 bpRunToCursor.ignore = 0;
3405 bpRunToCursor.level = -1;
3408 ExpressionType ::DebugEvalExpTypeError(char * result)
3414 case symbolNotFound:
3415 return symbolErrorExp;
3416 case memoryCantBeRead:
3417 return memoryErrorExp;
3419 return unknownErrorExp;
3422 char * ::EvaluateExpression(char * expression, ExpressionType * error)
3425 if(ide.projectView && ide.debugger.state == stopped)
3427 result = GdbEvaluateExpression(expression);
3428 *error = DebugEvalExpTypeError(result);
3433 *error = noDebuggerErrorExp;
3438 char * ::ReadMemory(uint address, int size, char format, ExpressionType * error)
3441 char * result = GdbReadMemoryString(address, size, format, 1, 1);
3442 if(!result || !strcmp(result, "N/A"))
3443 *error = memoryErrorExp;
3445 *error = DebugEvalExpTypeError(result);
3450 class GdbThread : Thread
3456 static char output[4096];
3457 Array<char> dynamicBuffer { minAllocSize = 4096 };
3458 DualPipe oldGdbHandle = gdbHandle;
3459 incref oldGdbHandle;
3462 while(debugger.state != terminated && gdbHandle && !gdbHandle.Eof())
3466 result = gdbHandle.Read(output, 1, sizeof(output));
3468 if(debugger.state == terminated || !gdbHandle || gdbHandle.Eof())
3475 for(c = 0; c<result; c++)
3477 if(output[c] == '\n')
3479 int pos = dynamicBuffer.size;
3480 dynamicBuffer.size += c - start;
3481 memcpy(&dynamicBuffer[pos], output + start, c - start);
3482 if(dynamicBuffer.count && dynamicBuffer[dynamicBuffer.count - 1] != '\r')
3483 // COMMENTED OUT DUE TO ISSUE #135, FIXED
3484 //if(dynamicBuffer.array[dynamicBuffer.count - 1] != '\r')
3485 dynamicBuffer.size++;
3486 dynamicBuffer[dynamicBuffer.count - 1] = '\0';
3488 // printf("%s\n", dynamicBuffer.array);
3490 debugger.GdbThreadMain(&dynamicBuffer[0]);
3491 dynamicBuffer.size = 0;
3497 int pos = dynamicBuffer.size;
3498 dynamicBuffer.size += c - start;
3499 memcpy(&dynamicBuffer[pos], output + start, c - start);
3505 printf("Got end of file from GDB!\n");
3509 delete dynamicBuffer;
3510 //if(oldGdbHandle == gdbHandle)
3511 debugger.GdbThreadExit();
3512 delete oldGdbHandle;
3518 static define createFIFOMsg = $"err: Unable to create FIFO %s\n";
3519 static define openFIFOMsg = $"err: Unable to open FIFO %s for read\n";
3521 #if defined(__unix__)
3526 #include <sys/types.h>
3531 class ProgramThread : Thread
3537 bool fileCreated = false;
3539 static char output[1000];
3542 /*if(!mkfifo(progFifoPath, mask))
3549 ide.outputView.debugBox.Logf($"err: Unable to create FIFO %s\n", progFifoPath);
3553 if(FileExists(progFifoPath)) //fileCreated)
3555 fifoFile = FileOpen(progFifoPath, read);
3559 ide.outputView.debugBox.Logf(openFIFOMsg, progFifoPath);
3564 fd = fileno((FILE *)fifoFile.input);
3565 //fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
3569 while(!terminate && fifoFile && !fifoFile.Eof())
3572 struct timeval time;
3580 selectResult = select(fd + 1, &rs, null, null, &time);
3581 if(FD_ISSET(fd, &rs))
3583 int result = read(fd, output, sizeof(output)-1);
3584 if(!result || (result < 0 && errno != EAGAIN))
3588 output[result] = '\0';
3589 if(strcmp(output,"&\"warning: GDB: Failed to set controlling terminal: Invalid argument\\n\"\n"))
3592 ide.outputView.debugBox.Log(output);
3601 //fifoFile.CloseInput();
3604 ide.outputView.debugBox.Log("\n");
3608 if(FileExists(progFifoPath)) //fileCreated)
3610 DeleteFile(progFifoPath);
3611 progFifoPath[0] = '\0';
3619 class Argument : struct
3621 Argument prev, next;
3637 class Frame : struct
3646 property char * from { set { delete from; if(value) from = CopyUnescapedUnixPath(value); } }
3648 property char * file { set { delete file; if(value) file = CopyUnescapedUnixPath(value); } }
3649 char * absoluteFile;
3658 delete absoluteFile;
3659 args.Free(Argument::Free);
3668 class GdbDataStop : struct
3685 char * gdbResultVar;
3695 if(!strcmp(reason, "signal-received"))
3700 else if(!strcmp(reason, "function-finished"))
3702 delete gdbResultVar;
3707 if(frame) frame.Free();
3716 class GdbDataBreakpoint : struct
3725 property char * file { set { delete file; if(value) file = CopyUnescapedUnixPath(value); } }
3740 ~GdbDataBreakpoint()
3746 class Breakpoint : struct
3750 char * relativeFilePath;
3751 char * absoluteFilePath;
3760 BreakpointType type;
3763 GdbDataBreakpoint bp;
3765 char * LocationToString()
3767 char location[MAX_LOCATION+20];
3768 sprintf(location, "%s:%d", relativeFilePath, line);
3769 #if defined(__WIN32__)
3770 ChangeCh(location, '/', '\\');
3772 return CopyString(location);
3777 if(relativeFilePath && relativeFilePath[0])
3779 f.Printf(" * %d,%d,%d,%d,%s\n", enabled ? 1 : 0, ignore, level, line, relativeFilePath);
3781 f.Printf(" ~ %s\n", condition.expression);
3790 delete relativeFilePath;
3791 delete absoluteFilePath;
3801 class Watch : struct
3812 f.Printf(" ~ %s\n", expression);
3836 class DebugListItem : struct
3842 struct DebugEvaluationData
3847 uint nextBlockAddress;
3849 DebuggerEvaluationError error;
3852 class CodeLocation : struct
3855 char * absoluteFile;
3858 CodeLocation ::ParseCodeLocation(char * location)
3862 char * colon = null;
3864 char loc[MAX_LOCATION];
3865 strcpy(loc, location);
3866 for(temp = loc; temp = strstr(temp, ":"); temp++)
3874 int line = atoi(colon);
3877 CodeLocation codloc { line = line };
3878 codloc.file = CopyString(loc);
3879 codloc.absoluteFile = ide.workspace.GetAbsolutePathFromRelative(loc);
3891 delete absoluteFile;