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;
319 static bool breakpointError;
323 Semaphore serialSemaphore { };
328 //bool breakpointsInserted;
330 bool sentBreakInsert;
331 bool ignoreBreakpoints;
332 bool userBreakOnInternBreak;
339 int activeFrameLevel;
350 DebuggerAction breakType;
351 //DebuggerCommand lastCommand; // THE COMPILER COMPILES STUFF THAT DOES NOT EXIST???
353 GdbDataStop stopItem;
354 GdbDataBreakpoint bpItem;
357 List<Breakpoint> sysBPs { };
358 Breakpoint bpRunToCursor;
364 CompilerConfig currentCompiler;
365 ProjectConfig prjConfig;
367 CodeEditor codeEditor;
369 GdbThread gdbThread { debugger = this };
372 delay = 0.0, userData = this;
376 bool monitor = false;
377 DebuggerEvent curEvent = event;
378 GdbDataStop stopItem = this.stopItem;
384 this.stopItem = null;
387 if(curEvent && curEvent != exit)
390 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*/);
503 ideMainFrame.Activate(); // TOFIX: ide.Activate() is not reliable (app inactive)
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 // GDB 6.3 on OS X is giving "fullname" and "dir", all in absolute, but file name only in 'file'
1373 String path = ide.workspace.GetPathWorkspaceRelativeOrAbsolute(item.value);
1374 if(strcmp(frame.file, path))
1377 delete frame.absoluteFile;
1378 frame.absoluteFile = ide.workspace.GetAbsolutePathFromRelative(frame.file);
1383 DebuggerProtocolUnknown("Unknown frame member name", item.name);
1386 DebuggerProtocolUnknown("Bad frame", "");
1391 delete argumentTokens;
1395 void ShowDebuggerViews()
1397 ide.outputView.Show();
1398 ide.outputView.SelectTab(debug);
1399 ide.threadsView.Show();
1400 ide.callStackView.Show();
1401 ide.watchesView.Show();
1405 void HideDebuggerViews()
1407 ide.RepositionWindows(true);
1410 void ::GdbCommand(bool focus, char * format, ...)
1414 // TODO: Improve this limit
1415 static char string[MAX_F_STRING*3];
1418 va_start(args, format);
1419 vsprintf(string, format, args);
1423 ide.debugger.serialSemaphore.TryWait();
1426 #ifdef GDB_DEBUG_CONSOLE
1427 Log(string); Log("\n");
1429 #ifdef GDB_DEBUG_OUTPUT
1430 ide.outputView.gdbBox.Logf("cmd: %s\n", string);
1432 #ifdef GDB_DEBUG_GUI
1434 ide.gdbDialog.AddCommand(string);
1436 strcat(string,"\n");
1437 gdbHandle.Puts(string);
1440 Process_ShowWindows(targetProcessId);
1443 ide.debugger.serialSemaphore.Wait();
1448 bool ValidateBreakpoint(Breakpoint bp)
1450 if(modules && bp.bp)
1452 if(bp.bp.line != bp.line)
1457 ide.outputView.debugBox.Logf("WOULD HAVE -- Invalid breakpoint disabled: %s:%d\n", bp.relativeFilePath, bp.line);
1461 //GdbCommand(false, "-break-delete %d", bp.bp.number);
1462 //bp.inserted = false;
1464 //bp.enabled = false;
1469 ide.outputView.debugBox.Logf("Debugger Error: ValidateBreakpoint error\n");
1470 bp.line = bp.bp.line;
1477 static void GdbInsertInternalBreakpoint()
1481 //if(!breakpointsInserted)
1483 DirExpression objDir = ide.project.GetObjDir(currentCompiler, prjConfig);
1488 if(bp.type == internalMain)
1490 sentBreakInsert = true;
1491 GdbCommand(false, "-break-insert main");
1494 bp.inserted = (bp.bp && bp.bp.number != 0);
1496 #if defined(__WIN32__)
1497 else if(bp.type == internalWinMain)
1499 sentBreakInsert = true;
1500 GdbCommand(false, "-break-insert WinMain");
1503 bp.inserted = (bp.bp && bp.bp.number != 0);
1506 else if(bp.type == internalModulesLoaded)
1508 char path[MAX_LOCATION];
1509 char name[MAX_LOCATION];
1510 char fixedModuleName[MAX_FILENAME];
1513 bool moduleLoadBlock = false;
1515 ReplaceSpaces(fixedModuleName, ide.project.moduleName);
1516 sprintf(name, "%s.main.ec", fixedModuleName);
1517 strcpy(path, ide.workspace.projectDir);
1518 PathCatSlash(path, objDir.dir);
1519 PathCatSlash(path, name);
1520 f = FileOpen(path, read);
1523 for(lineNumber = 1; !f.Eof(); lineNumber++)
1525 if(f.GetLine(line, sizeof(line) - 1))
1527 bool moduleLoadLine;
1528 TrimLSpaces(line, line);
1529 moduleLoadLine = !strncmp(line, "eModule_Load", strlen("eModule_Load"));
1530 if(!moduleLoadBlock && moduleLoadLine)
1531 moduleLoadBlock = true;
1532 else if(moduleLoadBlock && !moduleLoadLine && strlen(line) > 0)
1538 char relative[MAX_LOCATION];
1539 bp.absoluteFilePath = CopyString(path);
1540 MakePathRelative(path, ide.workspace.projectDir, relative);
1541 delete bp.relativeFilePath;
1542 bp.relativeFilePath = CopyString(relative);
1543 bp.line = lineNumber;
1544 sentBreakInsert = true;
1545 GdbCommand(false, "-break-insert %s:%d", bp.relativeFilePath, lineNumber);
1548 bp.inserted = (bp.bp && bp.bp.number != 0);
1549 ValidateBreakpoint(bp);
1562 void GdbBreakpointsInsert()
1566 //if(!breakpointsInserted)
1568 //if(!ignoreBreakpoints)
1569 //breakpointsInserted = true;
1570 for(bp : ide.workspace.breakpoints)
1572 if(!bp.inserted && bp.type == user)
1574 if(!ignoreBreakpoints && bp.enabled)
1576 sentBreakInsert = true;
1577 breakpointError = false;
1578 GdbCommand(false, "-break-insert %s:%d", bp.relativeFilePath, bp.line);
1579 // Improve, GdbCommand should return a success value?
1582 char fileName[MAX_FILENAME];
1583 breakpointError = false;
1584 GetLastDirectory(bp.relativeFilePath, fileName);
1585 sentBreakInsert = true;
1586 GdbCommand(false, "-break-insert %s:%d", fileName, bp.line);
1590 bp.inserted = (bp.bp && bp.bp.number != 0);
1593 ValidateBreakpoint(bp);
1599 printf("problem\n");
1601 bp.bp = GdbDataBreakpoint { };
1605 if(bpRunToCursor && !bpRunToCursor.inserted)
1607 sentBreakInsert = true;
1608 GdbCommand(false, "-break-insert %s:%d", bpRunToCursor.relativeFilePath, bpRunToCursor.line);
1609 bpRunToCursor.bp = bpItem;
1611 bpRunToCursor.inserted = (bpRunToCursor.bp && bpRunToCursor.bp.number != 0);
1612 ValidateBreakpoint(bpRunToCursor);
1618 void GdbBreakpointsDelete(bool deleteRunToCursor)
1620 //breakpointsInserted = false;
1623 for(bp : ide.workspace.breakpoints)
1626 GdbCommand(false, "-break-delete %d", bp.bp.number);
1627 bp.inserted = false;
1629 //check here (reply form -break-delete, returns bpitem?)
1632 if(deleteRunToCursor && bpRunToCursor)
1634 GdbCommand(false, "-break-delete %d", bpRunToCursor.bp.number);
1635 bpRunToCursor.inserted = false;
1636 bpRunToCursor.bp = bpItem;
1637 //check here (reply form -break-delete, returns bpitem?)
1646 stackFrames.Free(Frame::Free);
1647 GdbCommand(false, "-stack-info-depth");
1649 GdbCommand(false, "-stack-info-depth 192");
1650 if(frameCount && frameCount <= 192)
1651 GdbCommand(false, "-stack-list-frames 0 %d", Min(frameCount-1, 191));
1654 GdbCommand(false, "-stack-list-frames 0 %d", Min(frameCount-1, 95));
1655 GdbCommand(false, "-stack-list-frames %d %d", Max(frameCount - 96, 96), frameCount - 1);
1657 GdbCommand(false, "");
1664 char escaped[MAX_LOCATION];
1665 strescpy(escaped, targetFile);
1666 GdbCommand(false, "file \"%s\"", escaped); //GDB/MI Missing Implementation -symbol-file, -target-attach
1671 for(prj : ide.workspace.projects)
1673 if(prj == ide.workspace.projects.firstIterator.data)
1676 //PrintLn("THIS: ", (String)prj.topNode.path);
1677 GdbCommand(false, "-environment-directory \"%s\"", prj.topNode.path);
1678 //GdbCommand(false, ""); // why this empty GDB command
1681 for(dir : ide.workspace.sourceDirs)
1683 GdbCommand(false, "-environment-directory \"%s\"", dir);
1684 //GdbCommand(false, ""); // why this empty GDB command
1686 GdbInsertInternalBreakpoint();
1692 void GdbTargetRelease()
1696 GdbBreakpointsDelete(true);
1697 GdbCommand(false, "file"); //GDB/MI Missing Implementation -target-detach
1703 void GdbDebugBreak(bool internal)
1708 breakType = DebuggerAction::internal;
1710 if(ide) ide.Update(null);
1712 if(Process_Break(targetProcessId)) //GdbCommand(false, "-exec-interrupt");
1713 serialSemaphore.Wait();
1716 ChangeState(loaded);
1717 targetProcessId = 0;
1722 ide.outputView.debugBox.Logf("Debugger Error: GdbDebugBreak with not target id should never happen\n");
1729 ShowDebuggerViews();
1730 GdbCommand(true, "-exec-run");
1733 void GdbExecContinue(bool focus)
1736 GdbCommand(focus, "-exec-continue");
1742 GdbCommand(true, "-exec-next");
1748 GdbCommand(true, "-exec-step");
1751 void GdbExecFinish()
1754 GdbCommand(true, "-exec-finish");
1757 void GdbExecCommon()
1759 ClearBreakDisplay();
1760 GdbBreakpointsInsert();
1763 #ifdef GDB_DEBUG_GUI
1764 void SendGDBCommand(char * command)
1766 DebuggerState oldState = state;
1771 GdbDebugBreak(true);
1774 GdbCommand(false, command);
1777 if(oldState == running)
1778 GdbExecContinue(false);
1782 void ClearBreakDisplay()
1785 activeFrameLevel = -1;
1796 stackFrames.Free(Frame::Free);
1797 WatchesCodeEditorLinkRelease();
1798 ide.callStackView.Clear();
1799 ide.threadsView.Clear();
1806 GdbCommand(false, "-interpreter-exec console \"kill\""); // should use -exec-abort -- GDB/MI implementation incomplete
1810 bool GdbInit(CompilerConfig compiler, ProjectConfig config)
1813 char oldDirectory[MAX_LOCATION];
1814 char tempPath[MAX_LOCATION];
1815 char command[MAX_LOCATION];
1816 Project project = ide.project;
1817 DirExpression targetDirExp = project.GetTargetDir(compiler, config);
1818 PathBackup pathBackup { };
1820 if(currentCompiler != compiler)
1822 delete currentCompiler;
1823 currentCompiler = compiler;
1824 incref currentCompiler;
1828 ChangeState(loaded);
1830 sentBreakInsert = false;
1831 breakpointError = 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(createFIFOMsg, 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 && stopItem.frame.line && 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);
2614 ideMainFrame.Activate(); // TOFIX: ide.Activate() is not reliable (app inactive)
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);
2639 ideMainFrame.Activate(); // TOFIX: ide.Activate() is not reliable (app inactive)
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;
3025 breakpointError = true;
3028 printf("problem\n");
3030 bpItem = GdbDataBreakpoint { };
3033 if(outTokens.count > 1 && TokenizeListItem(outTokens[1], item))
3035 if(!strcmp(item.name, "msg"))
3037 StripQuotes(item.value, item.value);
3040 eval.active = false;
3042 if(strstr(item.value, "No symbol") && strstr(item.value, "in current context"))
3043 eval.error = symbolNotFound;
3044 else if(strstr(item.value, "Cannot access memory at address"))
3045 eval.error = memoryCantBeRead;
3047 eval.error = unknown;
3049 else if(!strcmp(item.value, "Previous frame inner to this frame (corrupt stack?)"))
3052 else if(!strncmp(item.value, "Cannot access memory at address", 31))
3055 else if(!strcmp(item.value, "Cannot find bounds of current function"))
3057 ChangeState(stopped);
3058 gdbHandle.Printf("-exec-continue\n");
3060 else if(!strcmp(item.value, "ptrace: No such process."))
3062 ChangeState(loaded);
3063 targetProcessId = 0;
3065 else if(!strcmp(item.value, "Function \\\"WinMain\\\" not defined."))
3068 else if(!strcmp(item.value, "You can't do that without a process to debug."))
3070 ChangeState(loaded);
3071 targetProcessId = 0;
3073 else if(strstr(item.value, "No such file or directory."))
3075 ChangeState(loaded);
3076 targetProcessId = 0;
3078 else if(strstr(item.value, "During startup program exited with code "))
3080 ChangeState(loaded);
3081 targetProcessId = 0;
3086 if(strlen(item.value) < MAX_F_STRING)
3089 ide.outputView.debugBox.Logf("GDB: %s\n", (s = CopyUnescapedString(item.value)));
3093 ide.outputView.debugBox.Logf("GDB: %s\n", item.value);
3099 DebuggerProtocolUnknown("Unknown error content", item.name);
3102 DebuggerProtocolUnknown("Unknown result-record", outTokens[0]);
3104 outTokens.RemoveAll();
3107 DebuggerProtocolUnknown("Unknown status-async-output", outTokens[0]);
3110 if(TokenizeList(output, ',', outTokens) && !strcmp(outTokens[0], "=thread-group-created")) //=thread-group-created,id="7611"
3112 else if(!strcmp(outTokens[0], "=thread-created")) //=thread-created,id="1",group-id="7611"
3114 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"
3117 DebuggerProtocolUnknown("Unknown notify-async-output", outTokens[0]);
3118 outTokens.RemoveAll();
3122 if(TokenizeList(output, ',', outTokens))
3124 if(!strcmp(outTokens[0],"*running"))
3126 waitingForPID = true;
3127 setWaitingForPID = true;
3129 else if(!strcmp(outTokens[0], "*stopped"))
3132 ChangeState(stopped);
3134 for(tk = 1; tk < outTokens.count; tk++)
3136 if(TokenizeListItem(outTokens[tk], item))
3138 if(!strcmp(item.name, "reason"))
3140 char * reason = item.value;
3141 StripQuotes(reason, reason);
3142 if(!strcmp(reason, "exited-normally") || !strcmp(reason, "exited") || !strcmp(reason, "exited-signalled"))
3145 if(outTokens.count > tk+1 && TokenizeListItem(outTokens[tk+1], item2))
3148 StripQuotes(item2.value, item2.value);
3149 if(!strcmp(item2.name, "exit-code"))
3150 exitCode = item2.value;
3156 HandleExit(reason, exitCode);
3158 else if(!strcmp(reason, "breakpoint-hit"))
3162 printf("problem\n");
3164 stopItem = GdbDataStop { };
3166 for(i = tk+1; i < outTokens.count; i++)
3168 TokenizeListItem(outTokens[i], item);
3169 StripQuotes(item.value, item.value);
3170 if(!strcmp(item.name, "bkptno"))
3171 stopItem.bkptno = atoi(item.value);
3172 else 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);
3180 DebuggerProtocolUnknown("Unknown breakpoint hit item name", item.name);
3185 else if(!strcmp(reason, "end-stepping-range"))
3189 printf("problem\n");
3191 stopItem = GdbDataStop { };
3193 for(i = tk+1; i < outTokens.count; i++)
3195 TokenizeListItem(outTokens[i], item);
3196 StripQuotes(item.value, item.value);
3197 if(!strcmp(item.name, "thread-id"))
3198 stopItem.threadid = atoi(item.value);
3199 else if(!strcmp(item.name, "frame"))
3201 item.value = StripCurlies(item.value);
3202 ParseFrame(stopItem.frame, item.value);
3204 else if(!strcmp(item.name, "reason"))
3206 else if(!strcmp(item.name, "bkptno"))
3209 DebuggerProtocolUnknown("Unknown end of stepping range item name", item.name);
3215 else if(!strcmp(reason, "function-finished"))
3219 printf("problem\n");
3221 stopItem = GdbDataStop { };
3222 stopItem.reason = CopyString(reason);
3224 for(i = tk+1; i < outTokens.count; i++)
3226 TokenizeListItem(outTokens[i], item);
3227 StripQuotes(item.value, item.value);
3228 if(!strcmp(item.name, "thread-id"))
3229 stopItem.threadid = atoi(item.value);
3230 else if(!strcmp(item.name, "frame"))
3232 item.value = StripCurlies(item.value);
3233 ParseFrame(stopItem.frame, item.value);
3235 else if(!strcmp(item.name, "gdb-result-var"))
3236 stopItem.gdbResultVar = CopyString(item.value);
3237 else if(!strcmp(item.name, "return-value"))
3238 stopItem.returnValue = CopyString(item.value);
3240 DebuggerProtocolUnknown("Unknown function finished item name", item.name);
3243 event = functionEnd;
3246 else if(!strcmp(reason, "signal-received"))
3250 printf("problem\n");
3252 stopItem = GdbDataStop { };
3253 stopItem.reason = CopyString(reason);
3255 for(i = tk+1; i < outTokens.count; i++)
3257 TokenizeListItem(outTokens[i], item);
3258 StripQuotes(item.value, item.value);
3259 if(!strcmp(item.name, "signal-name"))
3260 stopItem.name = CopyString(item.value);
3261 else if(!strcmp(item.name, "signal-meaning"))
3262 stopItem.meaning = CopyString(item.value);
3263 else if(!strcmp(item.name, "thread-id"))
3264 stopItem.threadid = atoi(item.value);
3265 else if(!strcmp(item.name, "frame"))
3267 item.value = StripCurlies(item.value);
3268 ParseFrame(stopItem.frame, item.value);
3271 DebuggerProtocolUnknown("Unknown signal reveived item name", item.name);
3273 if(!strcmp(stopItem.name, "SIGTRAP"))
3292 else if(!strcmp(reason, "watchpoint-trigger"))
3293 DebuggerProtocolUnknown("Reason watchpoint trigger not handled", "");
3294 else if(!strcmp(reason, "read-watchpoint-trigger"))
3295 DebuggerProtocolUnknown("Reason read watchpoint trigger not handled", "");
3296 else if(!strcmp(reason, "access-watchpoint-trigger"))
3297 DebuggerProtocolUnknown("Reason access watchpoint trigger not handled", "");
3298 else if(!strcmp(reason, "watchpoint-scope"))
3299 DebuggerProtocolUnknown("Reason watchpoint scope not handled", "");
3300 else if(!strcmp(reason, "location-reached"))
3301 DebuggerProtocolUnknown("Reason location reached not handled", "");
3303 DebuggerProtocolUnknown("Unknown reason", reason);
3311 DebuggerProtocolUnknown("Unknown exec-async-output", outTokens[0]);
3312 outTokens.RemoveAll();
3315 if(!strcmpi(output, "(gdb) "))
3319 char exeFile[MAX_LOCATION];
3320 int oldProcessID = targetProcessId;
3321 GetLastDirectory(targetFile, exeFile);
3325 targetProcessId = Process_GetChildExeProcessId(gdbProcessId, exeFile);
3326 if(targetProcessId || gdbHandle.Peek()) break;
3331 ChangeState(running);
3332 else if(!oldProcessID)
3334 ide.outputView.debugBox.Logf($"Debugger Error: No target process ID\n");
3335 // TO VERIFY: The rest of this block has not been thoroughly tested in this particular location
3336 gdbHandle.Printf("-gdb-exit\n");
3338 ChangeState(terminated); //loaded;
3343 for(bp : ide.workspace.breakpoints)
3344 bp.inserted = false;
3347 bp.inserted = false;
3349 bpRunToCursor.inserted = false;
3351 ide.outputView.debugBox.Logf($"Debugging stopped\n");
3352 ClearBreakDisplay();
3354 #if defined(__unix__)
3355 if(FileExists(progFifoPath)) //fileCreated)
3357 progThread.terminate = true;
3360 fifoFile.CloseInput();
3367 DeleteFile(progFifoPath);
3368 progFifoPath[0] = '\0';
3375 serialSemaphore.Release();
3378 DebuggerProtocolUnknown($"Unknown prompt", output);
3382 if(!strncmp(output, "&\"warning:", 10))
3385 content = strstr(output, "\"");
3386 StripQuotes(content, content);
3387 content = strstr(content, ":");
3393 ide.outputView.debugBox.LogRaw((s = CopyUnescapedString(content)));
3400 DebuggerProtocolUnknown($"Unknown output", output);
3402 if(!setWaitingForPID)
3403 waitingForPID = false;
3404 setWaitingForPID = false;
3412 void RunToCursorPrepare(char * absoluteFilePath, char * relativeFilePath, int lineNumber)
3416 //bpRunToCursor.Free();
3417 bpRunToCursor = Breakpoint { };
3420 bpRunToCursor = Breakpoint { };
3422 if(absoluteFilePath)
3423 bpRunToCursor.absoluteFilePath = CopyString(absoluteFilePath);
3424 if(relativeFilePath)
3425 bpRunToCursor.relativeFilePath = CopyString(relativeFilePath);
3426 bpRunToCursor.line = lineNumber;
3427 bpRunToCursor.type = runToCursor;
3428 bpRunToCursor.enabled = true;
3429 bpRunToCursor.condition = null;
3430 bpRunToCursor.ignore = 0;
3431 bpRunToCursor.level = -1;
3434 ExpressionType ::DebugEvalExpTypeError(char * result)
3440 case symbolNotFound:
3441 return symbolErrorExp;
3442 case memoryCantBeRead:
3443 return memoryErrorExp;
3445 return unknownErrorExp;
3448 char * ::EvaluateExpression(char * expression, ExpressionType * error)
3451 if(ide.projectView && ide.debugger.state == stopped)
3453 result = GdbEvaluateExpression(expression);
3454 *error = DebugEvalExpTypeError(result);
3459 *error = noDebuggerErrorExp;
3464 char * ::ReadMemory(uint address, int size, char format, ExpressionType * error)
3467 char * result = GdbReadMemoryString(address, size, format, 1, 1);
3468 if(!result || !strcmp(result, "N/A"))
3469 *error = memoryErrorExp;
3471 *error = DebugEvalExpTypeError(result);
3476 class GdbThread : Thread
3482 static char output[4096];
3483 Array<char> dynamicBuffer { minAllocSize = 4096 };
3484 DualPipe oldGdbHandle = gdbHandle;
3485 incref oldGdbHandle;
3488 while(debugger.state != terminated && gdbHandle && !gdbHandle.Eof())
3492 result = gdbHandle.Read(output, 1, sizeof(output));
3494 if(debugger.state == terminated || !gdbHandle || gdbHandle.Eof())
3501 for(c = 0; c<result; c++)
3503 if(output[c] == '\n')
3505 int pos = dynamicBuffer.size;
3506 dynamicBuffer.size += c - start;
3507 memcpy(&dynamicBuffer[pos], output + start, c - start);
3508 if(dynamicBuffer.count && dynamicBuffer[dynamicBuffer.count - 1] != '\r')
3509 // COMMENTED OUT DUE TO ISSUE #135, FIXED
3510 //if(dynamicBuffer.array[dynamicBuffer.count - 1] != '\r')
3511 dynamicBuffer.size++;
3512 dynamicBuffer[dynamicBuffer.count - 1] = '\0';
3514 // printf("%s\n", dynamicBuffer.array);
3516 debugger.GdbThreadMain(&dynamicBuffer[0]);
3517 dynamicBuffer.size = 0;
3523 int pos = dynamicBuffer.size;
3524 dynamicBuffer.size += c - start;
3525 memcpy(&dynamicBuffer[pos], output + start, c - start);
3531 printf("Got end of file from GDB!\n");
3535 delete dynamicBuffer;
3536 //if(oldGdbHandle == gdbHandle)
3537 debugger.GdbThreadExit();
3538 delete oldGdbHandle;
3544 static define createFIFOMsg = $"err: Unable to create FIFO %s\n";
3545 static define openFIFOMsg = $"err: Unable to open FIFO %s for read\n";
3547 #if defined(__unix__)
3552 #include <sys/types.h>
3557 class ProgramThread : Thread
3563 bool fileCreated = false;
3565 static char output[1000];
3568 /*if(!mkfifo(progFifoPath, mask))
3575 ide.outputView.debugBox.Logf($"err: Unable to create FIFO %s\n", progFifoPath);
3579 if(FileExists(progFifoPath)) //fileCreated)
3581 fifoFile = FileOpen(progFifoPath, read);
3585 ide.outputView.debugBox.Logf(openFIFOMsg, progFifoPath);
3590 fd = fileno((FILE *)fifoFile.input);
3591 //fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
3595 while(!terminate && fifoFile && !fifoFile.Eof())
3598 struct timeval time;
3606 selectResult = select(fd + 1, &rs, null, null, &time);
3607 if(FD_ISSET(fd, &rs))
3609 int result = read(fd, output, sizeof(output)-1);
3610 if(!result || (result < 0 && errno != EAGAIN))
3614 output[result] = '\0';
3615 if(strcmp(output,"&\"warning: GDB: Failed to set controlling terminal: Invalid argument\\n\"\n"))
3618 ide.outputView.debugBox.Log(output);
3627 //fifoFile.CloseInput();
3630 ide.outputView.debugBox.Log("\n");
3634 if(FileExists(progFifoPath)) //fileCreated)
3636 DeleteFile(progFifoPath);
3637 progFifoPath[0] = '\0';
3645 class Argument : struct
3647 Argument prev, next;
3663 class Frame : struct
3672 property char * from { set { delete from; if(value) from = CopyUnescapedUnixPath(value); } }
3674 property char * file { set { delete file; if(value) file = CopyUnescapedUnixPath(value); } }
3675 char * absoluteFile;
3684 delete absoluteFile;
3685 args.Free(Argument::Free);
3694 class GdbDataStop : struct
3711 char * gdbResultVar;
3721 if(!strcmp(reason, "signal-received"))
3726 else if(!strcmp(reason, "function-finished"))
3728 delete gdbResultVar;
3733 if(frame) frame.Free();
3742 class GdbDataBreakpoint : struct
3751 property char * file { set { delete file; if(value) file = CopyUnescapedUnixPath(value); } }
3766 ~GdbDataBreakpoint()
3772 class Breakpoint : struct
3776 char * relativeFilePath;
3777 char * absoluteFilePath;
3786 BreakpointType type;
3789 GdbDataBreakpoint bp;
3791 char * LocationToString()
3793 char location[MAX_LOCATION+20];
3794 sprintf(location, "%s:%d", relativeFilePath, line);
3795 #if defined(__WIN32__)
3796 ChangeCh(location, '/', '\\');
3798 return CopyString(location);
3803 if(relativeFilePath && relativeFilePath[0])
3805 f.Printf(" * %d,%d,%d,%d,%s\n", enabled ? 1 : 0, ignore, level, line, relativeFilePath);
3807 f.Printf(" ~ %s\n", condition.expression);
3816 delete relativeFilePath;
3817 delete absoluteFilePath;
3827 class Watch : struct
3838 f.Printf(" ~ %s\n", expression);
3862 class DebugListItem : struct
3868 struct DebugEvaluationData
3873 uint nextBlockAddress;
3875 DebuggerEvaluationError error;
3878 class CodeLocation : struct
3881 char * absoluteFile;
3884 CodeLocation ::ParseCodeLocation(char * location)
3888 char * colon = null;
3890 char loc[MAX_LOCATION];
3891 strcpy(loc, location);
3892 for(temp = loc; temp = strstr(temp, ":"); temp++)
3900 int line = atoi(colon);
3903 CodeLocation codloc { line = line };
3904 codloc.file = CopyString(loc);
3905 codloc.absoluteFile = ide.workspace.GetAbsolutePathFromRelative(loc);
3917 delete absoluteFile;