6 //#define GDB_DEBUG_CONSOLE
8 extern char * strrchr(char * s, char c);
20 #include <sys/time.h> // Required on Apple...
24 //bool eString_PathInsidePath(char * to, char * path)
25 bool eString_PathInsideOf(char * path, char * of)
27 if(!path[0] || !of[0])
28 return false; // What to do here? Ever used?
31 char ofPart[MAX_FILENAME], ofRest[MAX_LOCATION];
32 char pathPart[MAX_FILENAME], pathRest[MAX_LOCATION];
34 strcpy(pathRest, path);
35 for(; ofRest[0] && pathRest[0];)
37 SplitDirectory(ofRest, ofPart, ofRest);
38 SplitDirectory(pathRest, pathPart, pathRest);
39 if(fstrcmp(pathPart, ofPart))
42 if(!ofRest[0] && !pathRest[0]) // paths are identical - should return false or true? (changed to false)
44 else if(!pathRest[0]) // not inside of, it's the other way around
50 public char * StripQuotes2(char * string, char * output)
54 bool quoted = false, escaped = false;
56 for(c = 0; ch = string[c]; c++)
60 if(escaped || ch != '\"')
79 static void strescpy(char * d, char * s)
132 static char * CopyUnescapedSystemPath(char * p)
134 char * d = new char[strlen(p) + 1];
136 #if defined(__WIN32__)
137 ChangeCh(d, '/', '\\');
142 static char * CopyUnescapedUnixPath(char * p)
144 char * d = new char[strlen(p) + 1];
146 #if defined(__WIN32__)
147 ChangeCh(d, '\\', '/');
152 static char * CopyUnescapedString(char * s)
154 char * d = new char[strlen(s) + 1];
159 // String Unescape Copy
161 // TOFIX: THIS DOESN'T HANDLE NUMERIC ESCAPE CODES (OCTAL/HEXADECIMAL...)?
162 // Seems very similar to ReadString in pass15.ec (which also misses numeric escape codes :) )
164 static void struscpy(char * d, char * s)
216 static char * StripBrackets(char * string)
218 int length = strlen(string);
219 if(length > 1 && *string == '[' && string[length - 1] == ']')
222 string[length - 1] = '\0';
229 static char * StripCurlies(char * string)
231 int length = strlen(string);
232 if(length > 1 && *string == '{' && string[length - 1] == '}')
235 string[length - 1] = '\0';
242 static int StringGetInt(char * string, int start)
245 int i, len = strlen(string);
247 for(i = start; i < len && i < start + 8; i++)
249 if(string[i] == '0' || string[i] == '1' || string[i] == '2' || string[i] == '3' || string[i] == '4' || string[i] == '5' || string[i] == '6' || string[i] == '7' || string[i] == '8' || string[i] == '9')
250 strncat(number, &string[i], 1);
257 static int TokenizeList(char * string, const char seperator, Array<char *> tokens)
261 bool quoted = false; //bool escaped = false;
262 char * start = string;
264 for(; *string; string++)
273 else if(*string == '\"')
275 else if(*string == '{' || *string == '[' || *string == '(' || *string == '<')
277 else if(*string == '}' || *string == ']' || *string == ')' || *string == '>')
279 else if(*string == seperator && !level)
288 //tokens[count] = start;
289 //tokens[count++] = start;
296 static bool TokenizeListItem(char * string, DebugListItem item)
298 char * equal = strstr(string, "=");
312 static void DebuggerProtocolUnknown(char * message, char * gdbOutput)
314 #ifdef _DEBUG_GDB_PROTOCOL
315 ide.outputView.debugBox.Logf("Debugger Protocol Error: %s (%s)\n", message, gdbOutput);
319 // define GdbGetLineSize = 1638400;
320 define GdbGetLineSize = 5638400;
321 #if defined(__unix__)
322 char progFifoPath[MAX_LOCATION];
323 char progFifoDir[MAX_LOCATION];
326 enum DebuggerState { none, prompt, loaded, running, stopped, terminated };
327 enum DebuggerEvent { none, hit, breakEvent, signal, stepEnd, functionEnd, exit };
328 enum DebuggerAction { none, internal, restart, stop, selectFrame }; //, bpValidation
329 enum BreakpointType { none, internalMain, internalWinMain, internalModulesLoaded, user, runToCursor };
330 enum DebuggerEvaluationError { none, symbolNotFound, memoryCantBeRead, unknown };
332 FileDialog debuggerFileDialog { type = selectDir };
334 static DualPipe gdbHandle;
335 static DebugEvaluationData eval { };
337 static int targetProcessId;
339 static bool gdbReady;
343 Semaphore serialSemaphore { };
348 //bool breakpointsInserted;
350 bool sentBreakInsert;
351 bool ignoreBreakpoints;
352 bool userBreakOnInternBreak;
359 int activeFrameLevel;
370 DebuggerAction breakType;
371 //DebuggerCommand lastCommand; // THE COMPILER COMPILES STUFF THAT DOES NOT EXIST???
373 GdbDataStop stopItem;
374 GdbDataBreakpoint bpItem;
377 List<Breakpoint> sysBPs { };
378 Breakpoint bpRunToCursor;
384 CompilerConfig currentCompiler;
385 ProjectConfig prjConfig;
387 CodeEditor codeEditor;
389 GdbThread gdbThread { debugger = this };
392 delay = 0.0, userData = this;
396 bool monitor = false;
397 DebuggerEvent curEvent = event;
398 GdbDataStop stopItem = this.stopItem;
404 this.stopItem = null;
407 if(curEvent && curEvent != exit)
410 printf("No stop item\n");
419 Restart(currentCompiler, prjConfig);
428 GdbCommand(false, "-stack-select-frame %d", activeFrameLevel);
429 for(activeFrame = stackFrames.first; activeFrame; activeFrame = activeFrame.next)
430 if(activeFrame.level == activeFrameLevel)
436 // GdbCommand(false, "-break-info %d", bpItem.number);
446 activeThread = stopItem.threadid;
447 GdbCommand(false, "-thread-list-ids");
452 Breakpoint bp = null;
454 for(i : ide.workspace.breakpoints; i.bp && i.bp.number == stopItem.bkptno)
461 for(i : sysBPs; i.bp && i.bp.number == stopItem.bkptno)
469 if(!(!userBreakOnInternBreak &&
470 bp && (bp.type == internalMain || bp.type == internalWinMain || bp.type == internalModulesLoaded)))
472 hitThread = stopItem.threadid;
476 signalThread = stopItem.threadid;
488 activeThread = stopItem.threadid;
489 GdbCommand(false, "-thread-list-ids");
491 if(activeFrameLevel > 0)
492 GdbCommand(false, "-stack-select-frame %d", activeFrameLevel);
494 WatchesCodeEditorLinkInit();
504 ide.outputView.debugBox.Logf($"Signal received: %s - %s\n", stopItem.name, stopItem.meaning);
505 ide.outputView.debugBox.Logf(" %s:%d\n", (s = CopySystemPath(stopItem.frame.file)), stopItem.frame.line);
511 // Why was SelectFrame missing here?
512 SelectFrame(activeFrameLevel);
513 GoToStackFrameLine(activeFrameLevel, curEvent == signal || curEvent == stepEnd /*false*/);
516 if(curEvent == signal)
517 ide.outputView.Show();
518 if(curEvent == signal || curEvent == breakEvent)
520 if(curEvent == breakEvent)
521 ide.threadsView.Show();
522 ide.callStackView.Show();
524 ide.ShowCodeEditor();
525 if(curEvent == breakEvent)
526 ide.callStackView.Activate();
533 if(curEvent == DebuggerEvent::breakEvent || curEvent == stepEnd || curEvent == functionEnd)
534 ignoreBreakpoints = false;
545 #ifdef GDB_DEBUG_CONSOLE
546 char lastGdbOutput[GdbGetLineSize];
548 #if defined(__unix__)
549 ProgramThread progThread { };
552 void ChangeState(DebuggerState value)
555 if(ide) ide.AdjustDebugMenus();
560 // Stop(); // Don't need to call Stop here, because ~ProjectView() will call it explicitly.
562 stackFrames.Free(Frame::Free);
572 waitingForPID = false;
577 sentBreakInsert = false;
578 ignoreBreakpoints = false;
579 userBreakOnInternBreak = false;
582 activeFrameLevel = 0;
599 bpRunToCursor = null;
602 delete currentCompiler;
606 /*GdbThread gdbThread
612 ideProcessId = Process_GetCurrentProcessId();
614 sysBPs.Add(Breakpoint { type = internalMain, enabled = true, level = -1 });
615 #if defined(__WIN32__)
616 sysBPs.Add(Breakpoint { type = internalWinMain, enabled = true, level = -1 });
618 sysBPs.Add(Breakpoint { type = internalModulesLoaded, enabled = true, level = -1 });
631 property bool isActive { get { return state == running || state == stopped; } }
632 property bool isPrepared { get { return state == loaded || state == running || state == stopped; } }
636 GdbExecContinue(true);
645 //ide.AdjustDebugMenus();
646 GdbDebugBreak(false);
659 GdbDebugBreak(false);
670 void Restart(CompilerConfig compiler, ProjectConfig config)
678 GdbDebugBreak(false);
685 if(!GdbInit(compiler, config))
693 bool GoToCodeLine(char * location)
696 codloc = CodeLocation::ParseCodeLocation(location);
699 CodeEditor editor = (CodeEditor)ide.OpenFile(codloc.absoluteFile, normal, true, null, no, normal);
702 EditBox editBox = editor.editBox;
703 editBox.GoToLineNum(codloc.line - 1);
704 editBox.GoToPosition(editBox.line, codloc.line - 1, 0);
711 bool GoToStackFrameLine(int stackLevel, bool askForLocation)
715 char filePath[MAX_LOCATION];
716 char sourceDir[MAX_LOCATION];
718 CodeEditor editor = null;
719 if(stackLevel == -1) // this (the two lines) is part of that fix that I would not put in for some time
721 for(frame = stackFrames.first; frame; frame = frame.next)
722 if(frame.level == stackLevel)
726 ide.callStackView.Show();
728 if(!frame.absoluteFile && frame.file)
729 frame.absoluteFile = ide.workspace.GetAbsolutePathFromRelative(frame.file);
730 if(!frame.absoluteFile && askForLocation && frame.file)
733 char title[MAX_LOCATION];
735 sprintf(title, $"Provide source file location for %s", (s = CopySystemPath(frame.file)));
737 if(SourceDirDialog(title, ide.workspace.projectDir, frame.file, sourceDir))
739 AddSourceDir(sourceDir);
740 frame.absoluteFile = ide.workspace.GetAbsolutePathFromRelative(frame.file);
743 if(frame.absoluteFile)
744 editor = (CodeEditor)ide.OpenFile(frame.absoluteFile, normal, true, null, no, normal);
746 if(editor && frame.line)
748 EditBox editBox = editor.editBox;
749 editBox.GoToLineNum(frame.line - 1);
750 editBox.GoToPosition(editBox.line, frame.line - 1, 0);
758 void SelectThread(int thread)
762 if(thread != activeThread)
764 activeFrameLevel = -1;
765 ide.callStackView.Clear();
766 GdbCommand(false, "-thread-select %d", thread);
768 // Why was SelectFrame missing here?
769 SelectFrame(activeFrameLevel);
770 GoToStackFrameLine(activeFrameLevel, true);
771 WatchesCodeEditorLinkRelease();
772 WatchesCodeEditorLinkInit();
776 ide.callStackView.Show();
780 void SelectFrame(int frame)
784 if(frame != activeFrameLevel || !codeEditor || !codeEditor.visible)
786 activeFrameLevel = frame; // there is no active frame number in the gdb reply
787 GdbCommand(false, "-stack-select-frame %d", activeFrameLevel);
788 for(activeFrame = stackFrames.first; activeFrame; activeFrame = activeFrame.next)
789 if(activeFrame.level == activeFrameLevel)
792 WatchesCodeEditorLinkRelease();
793 WatchesCodeEditorLinkInit();
800 void HandleExit(char * reason, char * code)
802 bool returnedExitCode = false;
803 char verboseExitCode[128];
805 ChangeState(loaded); // this state change seems to be superfluous, might be in case of gdb crash
809 sprintf(verboseExitCode, $" with exit code %s", code);
811 verboseExitCode[0] = '\0';
815 // ClearBreakDisplay();
819 for(wh : ide.workspace.watches)
821 if(wh.type) FreeType(wh.type);
824 ide.watchesView.UpdateWatch(wh);
828 //ide.AdjustDebugMenus();
830 #if defined(__unix__)
831 progThread.terminate = true;
834 fifoFile.CloseInput();
843 char program[MAX_LOCATION];
844 GetSystemPathBuffer(program, targetFile);
846 ide.outputView.debugBox.Logf($"The program %s has exited%s.\n", program, verboseExitCode);
847 else if(!strcmp(reason, "exited-normally"))
848 ide.outputView.debugBox.Logf($"The program %s has exited normally%s.\n", program, verboseExitCode);
849 else if(!strcmp(reason, "exited"))
850 ide.outputView.debugBox.Logf($"The program %s has exited%s.\n", program, verboseExitCode);
851 else if(!strcmp(reason, "exited-signalled"))
852 ide.outputView.debugBox.Logf($"The program %s has exited with a signal%s.\n", program, verboseExitCode);
854 ide.outputView.debugBox.Logf($"The program %s has exited (gdb provided an unknown reason)%s.\n", program, verboseExitCode);
859 void Start(CompilerConfig compiler, ProjectConfig config)
861 ide.outputView.debugBox.Clear();
866 if(!GdbInit(compiler, config))
874 void StepInto(CompilerConfig compiler, ProjectConfig config)
880 if(!GdbInit(compiler, config))
883 ide.outputView.ShowClearSelectTab(debug);
884 ide.outputView.debugBox.Logf($"Starting debug mode\n");
885 userBreakOnInternBreak = true;
894 void StepOver(CompilerConfig compiler, ProjectConfig config, bool ignoreBkpts)
900 if(!GdbInit(compiler, config))
903 ide.outputView.ShowClearSelectTab(debug);
904 ide.outputView.debugBox.Logf($"Starting debug mode\n");
905 ignoreBreakpoints = ignoreBkpts;
906 userBreakOnInternBreak = true;
910 ignoreBreakpoints = ignoreBkpts;
911 if(ignoreBreakpoints)
912 GdbBreakpointsDelete(true);
918 void StepOut(bool ignoreBkpts)
922 ignoreBreakpoints = ignoreBkpts;
923 if(ignoreBreakpoints)
924 GdbBreakpointsDelete(true);
929 void RunToCursor(CompilerConfig compiler, ProjectConfig config, char * absoluteFilePath, int lineNumber, bool ignoreBkpts)
931 char relativeFilePath[MAX_LOCATION];
932 DebuggerState oldState = state;
933 ignoreBreakpoints = ignoreBkpts;
934 if(!ide.projectView.GetRelativePath(absoluteFilePath, relativeFilePath))
935 strcpy(relativeFilePath, absoluteFilePath);
940 Start(compiler, config);
947 ide.outputView.ShowClearSelectTab(debug);
948 ide.outputView.debugBox.Logf($"Starting debug mode\n");
950 RunToCursorPrepare(absoluteFilePath, relativeFilePath, lineNumber);
951 sentBreakInsert = true;
952 GdbCommand(false, "-break-insert %s:%d", relativeFilePath, lineNumber);
953 bpRunToCursor.bp = bpItem;
955 bpRunToCursor.inserted = (bpRunToCursor.bp.number != 0);
956 ValidateBreakpoint(bpRunToCursor);
963 if(ignoreBreakpoints)
964 GdbBreakpointsDelete(false);
968 if(ignoreBreakpoints)
969 GdbBreakpointsDelete(false);
970 GdbExecContinue(true);
976 void GetCallStackCursorLine(bool * error, int * lineCursor, int * lineTopFrame)
978 if(activeFrameLevel == -1)
986 *error = signalOn && activeThread == signalThread;
987 *lineCursor = activeFrameLevel + 1;
988 *lineTopFrame = activeFrameLevel ? 1 : 0;
992 int GetMarginIconsLineNumbers(char * fileName, int lines[], bool enabled[], int max, bool * error, int * lineCursor, int * lineTopFrame)
994 char winFilePath[MAX_LOCATION];
995 char * absoluteFilePath = GetSlashPathBuffer(winFilePath, fileName);
997 Iterator<Breakpoint> it { ide.workspace.breakpoints };
998 while(it.Next() && count < max)
1000 Breakpoint bp = it.data;
1003 if(bp.absoluteFilePath && bp.absoluteFilePath[0] && !fstrcmp(bp.absoluteFilePath, absoluteFilePath))
1005 lines[count] = bp.line;
1006 enabled[count] = bp.enabled;
1011 if(activeFrameLevel == -1)
1019 *error = signalOn && activeThread == signalThread;
1020 if(activeFrame && activeFrame.absoluteFile && !fstrcmp(absoluteFilePath, activeFrame.absoluteFile))
1021 *lineCursor = activeFrame.line;
1024 if(activeFrame && stopItem && stopItem.frame && activeFrame.level == stopItem.frame.level)
1026 else if(stopItem && stopItem.frame && stopItem.frame.absoluteFile && !fstrcmp(absoluteFilePath, stopItem.frame.absoluteFile))
1027 *lineTopFrame = stopItem.frame.line;
1031 if(*lineTopFrame == *lineCursor && *lineTopFrame)
1037 void ChangeWatch(DataRow row, char * expression)
1039 Watch wh = (Watch)row.tag;
1042 delete wh.expression;
1044 wh.expression = CopyString(expression);
1047 Iterator<Watch> it { ide.workspace.watches };
1049 ide.workspace.watches.Delete(it.pointer);
1056 ide.workspace.watches.Add(wh);
1058 wh.expression = CopyString(expression);
1060 ide.workspace.Save();
1061 //if(expression && state == stopped)
1066 void MoveIcons(char * fileName, int lineNumber, int move, bool start)
1068 char winFilePath[MAX_LOCATION];
1069 char * absoluteFilePath = GetSlashPathBuffer(winFilePath, fileName);
1072 for(bpLink = ide.workspace.breakpoints.first; bpLink; bpLink = next)
1074 Breakpoint bp = (Breakpoint)bpLink.data;
1077 if(bp.type == user && bp.absoluteFilePath && !fstrcmp(bp.absoluteFilePath, absoluteFilePath))
1079 if(bp.line > lineNumber || (bp.line == lineNumber && start))
1081 if(move < 0 && (bp.line < lineNumber - move))
1082 ide.workspace.RemoveBreakpoint(bp);
1086 ide.breakpointsView.UpdateBreakpoint(bp.row);
1087 ide.workspace.Save();
1093 // moving code cursors is futile, on next step, stop, hit, cursors will be offset anyways
1096 bool SourceDirDialog(char * title, char * startDir, char * test, char * sourceDir)
1100 String srcDir = null;
1102 debuggerFileDialog.text = title;
1103 debuggerFileDialog.currentDirectory = startDir;
1104 debuggerFileDialog.master = ide;
1106 while(debuggerFileDialog.Modal())
1108 strcpy(sourceDir, debuggerFileDialog.filePath);
1109 if(!fstrcmp(ide.workspace.projectDir, sourceDir) &&
1110 MessageBox { type = yesNo, master = ide,
1111 contents = $"This is the project directory.\nWould you like to try again?",
1112 text = $"Invalid Source Directory" }.Modal() == no)
1116 for(dir : ide.workspace.sourceDirs)
1118 if(!fstrcmp(dir, sourceDir))
1126 MessageBox { type = yesNo, master = ide,
1127 contents = $"This source directory is already specified.\nWould you like to try again?",
1128 text = $"Invalid Source Directory" }.Modal() == no)
1134 char file[MAX_LOCATION];
1135 strcpy(file, sourceDir);
1136 PathCat(file, test);
1137 result = FileExists(file);
1139 MessageBox { type = yesNo, master = ide,
1140 contents = $"Unable to locate source file.\nWould you like to try again?",
1141 text = $"Invalid Source Directory" }.Modal() == no)
1155 void AddSourceDir(char * sourceDir)
1157 ide.workspace.sourceDirs.Add(CopyString(sourceDir));
1158 ide.workspace.Save();
1162 DebuggerState oldState = state;
1167 GdbDebugBreak(true);
1170 GdbCommand(false, "-environment-directory \"%s\"", sourceDir);
1173 if(oldState == running)
1174 GdbExecContinue(false);
1178 void ToggleBreakpoint(char * fileName, int lineNumber, Project prj)
1180 char winFilePath[MAX_LOCATION];
1181 char * absoluteFilePath = GetSlashPathBuffer(winFilePath, fileName);
1182 char absolutePath[MAX_LOCATION];
1183 char relativePath[MAX_LOCATION];
1184 char sourceDir[MAX_LOCATION];
1185 Breakpoint bp = null;
1187 strcpy(absolutePath, absoluteFilePath);
1188 for(i : ide.workspace.breakpoints; i.type == user && i.absoluteFilePath && !fstrcmp(i.absoluteFilePath, absolutePath) && i.line == lineNumber)
1197 ide.workspace.RemoveBreakpoint(bp);
1205 // FIXED: This is how it should have been... Source locations are only for files not in project
1206 // if(eString_PathInsideOf(absolutePath, ide.workspace.projectDir))
1207 // MakePathRelative(absolutePath, ide.workspace.projectDir, relativePath);
1208 bool result = false;
1210 result = prj.GetRelativePath(absolutePath, relativePath);
1212 ide.projectView.GetRelativePath(absolutePath, relativePath);
1213 //if(ide.projectView.GetRelativePath(absolutePath, relativePath));
1217 char title[MAX_LOCATION];
1218 char directory[MAX_LOCATION];
1219 StripLastDirectory(absolutePath, directory);
1220 sprintf(title, $"Provide source files location directory for %s", absolutePath);
1223 String srcDir = null;
1224 for(dir : ide.workspace.sourceDirs)
1226 if(eString_PathInsideOf(absolutePath, dir))
1228 MakePathRelative(absoluteFilePath, dir, relativePath);
1236 if(SourceDirDialog(title, directory, null, sourceDir))
1238 if(eString_PathInsideOf(absolutePath, sourceDir))
1240 AddSourceDir(sourceDir);
1241 MakePathRelative(absoluteFilePath, sourceDir, relativePath);
1244 else if(MessageBox { type = yesNo, master = ide,
1245 contents = $"You must provide a valid source directory in order to place a breakpoint in this file.\nWould you like to try again?",
1246 text = $"Invalid Source Directory" }.Modal() == no)
1249 else if(MessageBox { type = yesNo, master = ide,
1250 contents = $"You must provide a source directory in order to place a breakpoint in this file.\nWould you like to try again?",
1251 text = $"No Source Directory Provided" }.Modal() == no)
1255 ide.workspace.bpCount++;
1256 bp = { line = lineNumber, type = user, enabled = true, level = -1 };
1257 ide.workspace.breakpoints.Add(bp);
1258 bp.absoluteFilePath = CopyString(absolutePath);
1259 bp.relativeFilePath = CopyString(relativePath);
1260 ide.breakpointsView.AddBreakpoint(bp);
1265 DebuggerState oldState = state;
1270 GdbDebugBreak(true);
1275 sentBreakInsert = true;
1276 GdbCommand(false, "-break-insert %s:%d", bp.relativeFilePath, bp.line);
1279 bp.inserted = (bp.bp && bp.bp.number != 0);
1280 ValidateBreakpoint(bp);
1284 if(oldState == running)
1285 GdbExecContinue(false);
1288 ide.workspace.Save();
1291 void UpdateRemovedBreakpoint(Breakpoint bp)
1293 if(targeted && bp.inserted)
1295 DebuggerState oldState = state;
1300 GdbDebugBreak(true);
1304 GdbCommand(false, "-break-delete %d", bp.bp.number);
1307 if(oldState == running)
1308 GdbExecContinue(false);
1314 void ParseFrame(Frame frame, char * string)
1317 Array<char *> frameTokens { minAllocSize = 50 };
1318 Array<char *> argsTokens { minAllocSize = 50 };
1319 Array<char *> argumentTokens { minAllocSize = 50 };
1320 DebugListItem item { };
1323 TokenizeList(string, ',', frameTokens);
1324 for(i = 0; i < frameTokens.count; i++)
1326 if(TokenizeListItem(frameTokens[i], item))
1328 StripQuotes(item.value, item.value);
1329 if(!strcmp(item.name, "level"))
1330 frame.level = atoi(item.value);
1331 else if(!strcmp(item.name, "addr"))
1332 frame.addr = CopyString(item.value);
1333 else if(!strcmp(item.name, "func"))
1334 frame.func = CopyString(item.value);
1335 else if(!strcmp(item.name, "args"))
1337 if(!strcmp(item.value, "[]"))
1338 frame.argsCount = 0;
1341 item.value = StripBrackets(item.value);
1342 TokenizeList(item.value, ',', argsTokens);
1343 for(j = 0; j < argsTokens.count; j++)
1345 argsTokens[j] = StripCurlies(argsTokens[j]);
1346 TokenizeList(argsTokens[j], ',', argumentTokens);
1347 for(k = 0; k < argumentTokens.count; k++)
1350 frame.args.Add(arg);
1351 if(TokenizeListItem(argumentTokens[k], item))
1353 if(!strcmp(item.name, "name"))
1355 StripQuotes(item.value, item.value);
1356 arg.name = CopyString(item.value);
1358 else if(!strcmp(item.name, "value"))
1360 StripQuotes(item.value, item.value);
1361 arg.value = CopyString(item.value);
1364 DebuggerProtocolUnknown("Unknown frame args item name", item.name);
1367 DebuggerProtocolUnknown("Bad frame args item", "");
1369 argumentTokens.RemoveAll();
1371 frame.argsCount = argsTokens.count;
1372 argsTokens.RemoveAll();
1375 else if(!strcmp(item.name, "from"))
1376 frame.from = item.value;
1377 else if(!strcmp(item.name, "file"))
1379 frame.file = item.value;
1380 frame.absoluteFile = ide.workspace.GetAbsolutePathFromRelative(frame.file);
1382 else if(!strcmp(item.name, "line"))
1383 frame.line = atoi(item.value);
1384 else if(!strcmp(item.name, "fullname"))
1386 // New GDB is giving us a full name... Any reason why we coudln't figure it out ourselves?
1389 DebuggerProtocolUnknown("Unknown frame member name", item.name);
1392 DebuggerProtocolUnknown("Bad frame", "");
1397 delete argumentTokens;
1401 void ShowDebuggerViews()
1403 ide.outputView.Show();
1404 ide.outputView.SelectTab(debug);
1405 ide.threadsView.Show();
1406 ide.callStackView.Show();
1407 ide.watchesView.Show();
1411 void HideDebuggerViews()
1413 ide.RepositionWindows(true);
1416 void ::GdbCommand(bool focus, char * format, ...)
1420 char string[MAX_F_STRING];
1423 va_start(args, format);
1424 vsprintf(string, format, args);
1428 ide.debugger.serialSemaphore.TryWait();
1431 #ifdef GDB_DEBUG_CONSOLE
1432 Log(string); Log("\n");
1434 #ifdef GDB_DEBUG_OUTPUT
1435 ide.outputView.gdbBox.Logf("cmd: %s\n", string);
1437 #ifdef GDB_DEBUG_GUI
1439 ide.gdbDialog.AddCommand(string);
1441 gdbHandle.Printf("%s\n", string);
1444 Process_ShowWindows(targetProcessId);
1447 ide.debugger.serialSemaphore.Wait();
1452 bool ValidateBreakpoint(Breakpoint bp)
1456 if(bp.bp.line != bp.line)
1461 ide.outputView.debugBox.Logf("WOULD HAVE -- Invalid breakpoint disabled: %s:%d\n", bp.relativeFilePath, bp.line);
1465 //GdbCommand(false, "-break-delete %d", bp.bp.number);
1466 //bp.inserted = false;
1468 //bp.enabled = false;
1473 ide.outputView.debugBox.Logf("Debugger Error: ValidateBreakpoint error\n");
1474 bp.line = bp.bp.line;
1481 static void GdbInsertInternalBreakpoint()
1485 //if(!breakpointsInserted)
1487 DirExpression objDir = ide.project.GetObjDir(currentCompiler, prjConfig);
1492 if(bp.type == internalMain)
1494 sentBreakInsert = true;
1495 GdbCommand(false, "-break-insert main");
1498 bp.inserted = (bp.bp && bp.bp.number != 0);
1500 #if defined(__WIN32__)
1501 else if(bp.type == internalWinMain)
1503 sentBreakInsert = true;
1504 GdbCommand(false, "-break-insert WinMain");
1507 bp.inserted = (bp.bp && bp.bp.number != 0);
1510 else if(bp.type == internalModulesLoaded)
1512 char path[MAX_LOCATION];
1513 char name[MAX_LOCATION];
1514 char fixedModuleName[MAX_FILENAME];
1517 bool moduleLoadBlock = false;
1519 ReplaceSpaces(fixedModuleName, ide.project.moduleName);
1520 sprintf(name, "%s.main.ec", fixedModuleName);
1521 strcpy(path, ide.workspace.projectDir);
1522 PathCatSlash(path, objDir.dir);
1523 PathCatSlash(path, name);
1524 f = FileOpen(path, read);
1527 for(lineNumber = 1; !f.Eof(); lineNumber++)
1529 if(f.GetLine(line, sizeof(line) - 1))
1531 bool moduleLoadLine;
1532 TrimLSpaces(line, line);
1533 moduleLoadLine = !strncmp(line, "eModule_Load", strlen("eModule_Load"));
1534 if(!moduleLoadBlock && moduleLoadLine)
1535 moduleLoadBlock = true;
1536 else if(moduleLoadBlock && !moduleLoadLine && strlen(line) > 0)
1542 char relative[MAX_LOCATION];
1543 bp.absoluteFilePath = CopyString(path);
1544 MakePathRelative(path, ide.workspace.projectDir, relative);
1545 delete bp.relativeFilePath;
1546 bp.relativeFilePath = CopyString(relative);
1547 bp.line = lineNumber;
1548 sentBreakInsert = true;
1549 GdbCommand(false, "-break-insert %s:%d", bp.relativeFilePath, lineNumber);
1552 bp.inserted = (bp.bp && bp.bp.number != 0);
1553 ValidateBreakpoint(bp);
1566 void GdbBreakpointsInsert()
1570 //if(!breakpointsInserted)
1572 //if(!ignoreBreakpoints)
1573 //breakpointsInserted = true;
1574 for(bp : ide.workspace.breakpoints)
1576 if(!bp.inserted && bp.type == user)
1578 if(!ignoreBreakpoints && bp.enabled)
1580 sentBreakInsert = true;
1581 GdbCommand(false, "-break-insert %s:%d", bp.relativeFilePath, bp.line);
1584 bp.inserted = (bp.bp && bp.bp.number != 0);
1586 ValidateBreakpoint(bp);
1592 printf("problem\n");
1594 bp.bp = GdbDataBreakpoint { };
1598 if(bpRunToCursor && !bpRunToCursor.inserted)
1600 sentBreakInsert = true;
1601 GdbCommand(false, "-break-insert %s:%d", bpRunToCursor.relativeFilePath, bpRunToCursor.line);
1602 bpRunToCursor.bp = bpItem;
1604 bpRunToCursor.inserted = (bpRunToCursor.bp && bpRunToCursor.bp.number != 0);
1605 ValidateBreakpoint(bpRunToCursor);
1611 void GdbBreakpointsDelete(bool deleteRunToCursor)
1613 //breakpointsInserted = false;
1616 for(bp : ide.workspace.breakpoints)
1619 GdbCommand(false, "-break-delete %d", bp.bp.number);
1620 bp.inserted = false;
1622 //check here (reply form -break-delete, returns bpitem?)
1625 if(deleteRunToCursor && bpRunToCursor)
1627 GdbCommand(false, "-break-delete %d", bpRunToCursor.bp.number);
1628 bpRunToCursor.inserted = false;
1629 bpRunToCursor.bp = bpItem;
1630 //check here (reply form -break-delete, returns bpitem?)
1639 stackFrames.Free(Frame::Free);
1640 GdbCommand(false, "-stack-info-depth");
1642 GdbCommand(false, "-stack-info-depth 192");
1643 if(frameCount && frameCount <= 192)
1644 GdbCommand(false, "-stack-list-frames 0 191");
1647 GdbCommand(false, "-stack-list-frames 0 95");
1648 GdbCommand(false, "-stack-list-frames %d %d", Max(frameCount - 96, 96), frameCount - 1);
1650 GdbCommand(false, "");
1657 char escaped[MAX_LOCATION];
1658 strescpy(escaped, targetFile);
1659 GdbCommand(false, "file \"%s\"", escaped); //GDB/MI Missing Implementation -symbol-file, -target-attach
1664 for(prj : ide.workspace.projects)
1666 if(prj == ide.workspace.projects.firstIterator.data)
1669 //PrintLn("THIS: ", (String)prj.topNode.path);
1670 GdbCommand(false, "-environment-directory \"%s\"", prj.topNode.path);
1671 //GdbCommand(false, ""); // why this empty GDB command
1674 for(dir : ide.workspace.sourceDirs)
1676 GdbCommand(false, "-environment-directory \"%s\"", dir);
1677 //GdbCommand(false, ""); // why this empty GDB command
1679 GdbInsertInternalBreakpoint();
1685 void GdbTargetRelease()
1689 GdbBreakpointsDelete(true);
1690 GdbCommand(false, "file"); //GDB/MI Missing Implementation -target-detach
1696 void GdbDebugBreak(bool internal)
1701 breakType = DebuggerAction::internal;
1705 //ide.AdjustDebugMenus();
1709 if(Process_Break(targetProcessId)) //GdbCommand(false, "-exec-interrupt");
1710 serialSemaphore.Wait();
1713 ChangeState(loaded);
1714 targetProcessId = 0;
1715 //ide.AdjustDebugMenus();
1720 ide.outputView.debugBox.Logf("Debugger Error: GdbDebugBreak with not target id should never happen\n");
1727 ShowDebuggerViews();
1728 GdbCommand(true, "-exec-run");
1731 void GdbExecContinue(bool focus)
1734 GdbCommand(focus, "-exec-continue");
1740 GdbCommand(true, "-exec-next");
1746 GdbCommand(true, "-exec-step");
1749 void GdbExecFinish()
1752 GdbCommand(true, "-exec-finish");
1755 void GdbExecCommon()
1757 ClearBreakDisplay();
1758 GdbBreakpointsInsert();
1761 #ifdef GDB_DEBUG_GUI
1762 void SendGDBCommand(char * command)
1764 DebuggerState oldState = state;
1769 GdbDebugBreak(true);
1772 GdbCommand(false, command);
1775 if(oldState == running)
1776 GdbExecContinue(false);
1780 void ClearBreakDisplay()
1783 activeFrameLevel = -1;
1794 stackFrames.Free(Frame::Free);
1795 WatchesCodeEditorLinkRelease();
1796 ide.callStackView.Clear();
1797 ide.threadsView.Clear();
1804 GdbCommand(false, "-interpreter-exec console \"kill\""); // should use -exec-abort -- GDB/MI implementation incomplete
1808 bool GdbInit(CompilerConfig compiler, ProjectConfig config)
1811 char oldDirectory[MAX_LOCATION];
1812 char tempPath[MAX_LOCATION];
1813 char command[MAX_LOCATION];
1814 Project project = ide.project;
1815 DirExpression targetDirExp = project.GetTargetDir(compiler, config);
1816 PathBackup pathBackup { };
1818 if(currentCompiler != compiler)
1820 delete currentCompiler;
1821 currentCompiler = compiler;
1822 incref currentCompiler;
1826 ChangeState(loaded);
1828 sentBreakInsert = false;
1832 //breakpointsInserted = false;
1834 ide.outputView.ShowClearSelectTab(debug);
1835 ide.outputView.debugBox.Logf($"Starting debug mode\n");
1837 #ifdef GDB_DEBUG_CONSOLE
1838 Log("Starting GDB"); Log("\n");
1840 #ifdef GDB_DEBUG_OUTPUT
1841 ide.outputView.gdbBox.Logf("run: Starting GDB\n");
1844 strcpy(tempPath, ide.workspace.projectDir);
1845 PathCatSlash(tempPath, targetDirExp.dir);
1847 targetDir = CopyString(tempPath);
1848 project.CatTargetFileName(tempPath, compiler, config);
1850 targetFile = CopyString(tempPath);
1852 GetWorkingDir(oldDirectory, MAX_LOCATION);
1853 if(ide.workspace.debugDir && ide.workspace.debugDir[0])
1855 char temp[MAX_LOCATION];
1856 strcpy(temp, ide.workspace.projectDir);
1857 PathCatSlash(temp, ide.workspace.debugDir);
1858 ChangeWorkingDir(temp);
1861 ChangeWorkingDir(ide.workspace.projectDir);
1863 ide.SetPath(true, compiler, config);
1865 // TODO: This pollutes the environment, but at least it works
1866 // It shouldn't really affect the IDE as the PATH gets restored and other variables set for testing will unlikely cause problems
1867 // What is the proper solution for this? DualPipeOpenEnv?
1868 // gdb set environment commands don't seem to take effect
1869 for(e : ide.workspace.environmentVars)
1871 SetEnvironment(e.name, e.string);
1874 sprintf(command, "gdb -n -silent --interpreter=mi2"); //-async //\"%s\"
1876 gdbHandle = DualPipeOpen(PipeOpenMode { output = 1, error = 2, input = 1 }, command);
1879 ide.outputView.debugBox.Logf($"Debugger Fatal Error: Couldn't start GDB\n");
1887 gdbProcessId = gdbHandle.GetProcessID();
1890 ide.outputView.debugBox.Logf($"Debugger Fatal Error: Couldn't get GDB process ID\n");
1896 serialSemaphore.Wait();
1901 //ChangeState(terminated);
1902 //ide.AdjustDebugMenus();
1908 #if defined(__unix__)
1910 CreateTemporaryDir(progFifoDir, "ecereide");
1911 strcpy(progFifoPath, progFifoDir);
1912 PathCat(progFifoPath, "ideprogfifo");
1913 if(!mkfifo(progFifoPath, 0600))
1915 //fileCreated = true;
1920 ide.outputView.debugBox.Logf($"err: Unable to create FIFO %s\n", progFifoPath);
1925 progThread.terminate = false;
1926 progThread.Create();
1929 #if defined(__WIN32__)
1930 GdbCommand(false, "-gdb-set new-console on");
1933 GdbCommand(false, "-gdb-set verbose off");
1934 //GdbCommand(false, "-gdb-set exec-done-display on");
1935 GdbCommand(false, "-gdb-set step-mode off");
1936 GdbCommand(false, "-gdb-set unwindonsignal on");
1937 //GdbCommand(false, "-gdb-set shell on");
1938 GdbCommand(false, "set print elements 992");
1939 GdbCommand(false, "-gdb-set backtrace limit 100000");
1941 #if defined(__unix__)
1942 GdbCommand(false, "-inferior-tty-set %s", progFifoPath);
1945 GdbCommand(false, "-gdb-set args %s", ide.workspace.commandLineArgs ? ide.workspace.commandLineArgs : "");
1947 for(e : ide.workspace.environmentVars)
1949 GdbCommand(false, "set environment %s=%s", e.name, e.string);
1956 ChangeWorkingDir(oldDirectory);
1962 delete targetDirExp;
1968 if(gdbHandle && gdbProcessId)
1970 GdbCommand(false, "-gdb-exit");
1985 ChangeState(terminated); // this state change seems to be superfluous, is it safety for something?
1989 for(bp : ide.workspace.breakpoints)
1990 bp.inserted = false;
1992 bp.inserted = false;
1994 bpRunToCursor.inserted = false;
1996 ide.outputView.debugBox.Logf($"Debugging stopped\n");
1997 ClearBreakDisplay();
1998 //ide.AdjustDebugMenus();
2001 #if defined(__unix__)
2002 if(FileExists(progFifoPath)) //fileCreated)
2004 progThread.terminate = true;
2007 fifoFile.CloseInput();
2013 DeleteFile(progFifoPath);
2014 progFifoPath[0] = '\0';
2020 void WatchesCodeEditorLinkInit()
2023 char tempPath[MAX_LOCATION];
2024 char path[MAX_LOCATION];
2026 //void MakeFilePathProjectRelative(char * path, char * relativePath)
2027 if(!ide.projectView.GetRelativePath(activeFrame.file, tempPath))
2028 strcpy(tempPath, activeFrame.file);
2030 strcpy(path, ide.workspace.projectDir);
2031 PathCat(path, tempPath);
2032 codeEditor = (CodeEditor)ide.OpenFile(path, Normal, false, null, no);
2035 for(srcDir : ide.workspace.sourceDirs)
2037 strcpy(path, srcDir);
2038 PathCat(path, tempPath);
2039 codeEditor = (CodeEditor)ide.OpenFile(path, Normal, false, null, no);
2040 if(codeEditor) break;
2045 if(activeFrame && !activeFrame.absoluteFile && activeFrame.file)
2046 activeFrame.absoluteFile = ide.workspace.GetAbsolutePathFromRelative(activeFrame.file);
2047 if(!activeFrame || !activeFrame.absoluteFile)
2050 codeEditor = (CodeEditor)ide.OpenFile(activeFrame.absoluteFile, normal, false, null, no, normal);
2053 codeEditor.inUseDebug = true;
2056 //watchesInit = true;
2059 void WatchesCodeEditorLinkRelease()
2065 codeEditor.inUseDebug = false;
2066 if(!codeEditor.visible)
2067 codeEditor.Destroy(0);
2073 bool ResolveWatch(Watch wh)
2075 bool result = false;
2088 char watchmsg[MAX_F_STRING];
2089 if(state == stopped && !codeEditor)
2090 wh.value = CopyString($"No source file found for selected frame");
2091 //if(codeEditor && state == stopped || state != stopped)
2094 Module backupPrivateModule;
2095 Context backupContext;
2096 Class backupThisClass;
2100 backupPrivateModule = GetPrivateModule();
2101 backupContext = GetCurrentContext();
2102 backupThisClass = GetThisClass();
2105 SetPrivateModule(codeEditor.privateModule);
2106 SetCurrentContext(codeEditor.globalContext);
2107 SetTopContext(codeEditor.globalContext);
2108 SetGlobalContext(codeEditor.globalContext);
2109 SetGlobalData(&codeEditor.globalData);
2112 exp = ParseExpressionString(wh.expression);
2114 if(exp && !parseError)
2116 if(GetPrivateModule())
2119 DebugFindCtxTree(codeEditor.ast, activeFrame.line, 0);
2120 ProcessExpressionType(exp);
2122 wh.type = exp.expType;
2125 DebugComputeExpression(exp);
2127 /*if(exp.hasAddress)
2129 char temp[MAX_F_STRING];
2130 sprintf(temp, "0x%x", exp.address);
2131 wh.address = CopyString(temp);
2132 // wh.address = CopyStringf("0x%x", exp.address);
2137 Type dataType = exp.expType;
2140 char temp[MAX_F_STRING];
2141 switch(dataType.kind)
2144 sprintf(temp, "%i", exp.val.c);
2147 sprintf(temp, "%i", exp.val.s);
2152 sprintf(temp, "%i", exp.val.i);
2155 sprintf(temp, "%i", exp.val.i64);
2158 sprintf(temp, "%i", exp.val.p);
2163 long v = (long)exp.val.f;
2164 sprintf(temp, "%i", v);
2169 long v = (long)exp.val.d;
2170 sprintf(temp, "%i", v);
2175 wh.intVal = CopyString(temp);
2176 switch(dataType.kind)
2179 sprintf(temp, "0x%x", exp.val.c);
2182 sprintf(temp, "0x%x", exp.val.s);
2186 sprintf(temp, "0x%x", exp.val.i);
2189 sprintf(temp, "0x%x", exp.val.i64);
2192 sprintf(temp, "0x%x", exp.val.i64);
2195 sprintf(temp, "0x%x", exp.val.p);
2200 long v = (long)exp.val.f;
2201 sprintf(temp, "0x%x", v);
2206 long v = (long)exp.val.d;
2207 sprintf(temp, "0x%x", v);
2212 wh.hexVal = CopyString(temp);
2213 switch(dataType.kind)
2216 sprintf(temp, "0o%o", exp.val.c);
2219 sprintf(temp, "0o%o", exp.val.s);
2223 sprintf(temp, "0o%o", exp.val.i);
2226 sprintf(temp, "0o%o", exp.val.i64);
2229 sprintf(temp, "0o%o", exp.val.i64);
2232 sprintf(temp, "0o%o", exp.val.p);
2237 long v = (long)exp.val.f;
2238 sprintf(temp, "0o%o", v);
2243 long v = (long)exp.val.d;
2244 sprintf(temp, "0o%o", v);
2249 wh.octVal = CopyString(temp);
2252 // WHATS THIS HERE ?
2253 if(exp.type == constantExp && exp.constant)
2254 wh.constant = CopyString(exp.constant);
2260 case symbolErrorExp:
2261 sprintf(watchmsg, $"Symbol \"%s\" not found", exp.identifier.string);
2263 case structMemberSymbolErrorExp:
2264 // todo get info as in next case (ExpClassMemberSymbolError)
2265 sprintf(watchmsg, $"Error: Struct member not found for \"%s\"", wh.expression);
2267 case classMemberSymbolErrorExp:
2270 Expression memberExp = exp.member.exp;
2271 Identifier memberID = exp.member.member;
2272 Type type = memberExp.expType;
2275 _class = (memberID && memberID.classSym) ? memberID.classSym.registered : ((type.kind == classType && type._class) ? type._class.registered : null);
2278 char string[256] = "";
2280 PrintType(type, string, false, true);
2281 classSym = FindClass(string);
2282 _class = classSym ? classSym.registered : null;
2285 sprintf(watchmsg, $"Member \"%s\" not found in class \"%s\"", memberID ? memberID.string : "", _class.name);
2287 sprintf(watchmsg, "Member \"%s\" not found in unregistered class? (Should never get this message)", memberID ? memberID.string : "");
2290 sprintf(watchmsg, "Member \"%s\" not found in no type? (Should never get this message)", memberID ? memberID.string : "");
2293 case memoryErrorExp:
2294 // Need to ensure when set to memoryErrorExp, constant is set
2295 sprintf(watchmsg, $"Memory can't be read at %s", /*(exp.type == constantExp) ? */exp.constant /*: null*/);
2297 case dereferenceErrorExp:
2298 sprintf(watchmsg, $"Dereference failure for \"%s\"", wh.expression);
2300 case unknownErrorExp:
2301 sprintf(watchmsg, $"Unknown error for \"%s\"", wh.expression);
2303 case noDebuggerErrorExp:
2304 sprintf(watchmsg, $"Debugger required for symbol evaluation in \"%s\"", wh.expression);
2306 case debugStateErrorExp:
2307 sprintf(watchmsg, $"Incorrect debugger state for symbol evaluation in \"%s\"", wh.expression);
2310 sprintf(watchmsg, $"Null type for \"%s\"", wh.expression);
2314 // Temporary Code for displaying Strings
2315 if((exp.expType && ((exp.expType.kind == pointerType ||
2316 exp.expType.kind == arrayType) && exp.expType.type.kind == charType)) ||
2317 (wh.type && wh.type.kind == classType && wh.type._class &&
2318 wh.type._class.registered && wh.type._class.registered.type == normalClass &&
2319 !strcmp(wh.type._class.registered.name, "String")))
2322 if(exp.expType.kind != arrayType || exp.hasAddress)
2328 //char temp[MAX_F_STRING * 32];
2330 ExpressionType evalError = dummyExp;
2331 /*if(exp.expType.kind == arrayType)
2332 sprintf(temp, "(char*)0x%x", exp.address);
2334 sprintf(temp, "(char*)%s", exp.constant);*/
2336 //evaluation = Debugger::EvaluateExpression(temp, &evalError);
2337 address = strtoul(exp.constant, null, 0);
2338 //printf("%x\n", address);
2339 sprintf(value, "0x%08x ", address);
2342 strcat(value, $"Null string");
2346 len = strlen(value);
2348 while(!string && size > 2)
2350 string = GdbReadMemory(address, size);
2353 if(string && string[0])
2356 if(UTF8Validate(string))
2361 for(c = 0; (ch = string[c]) && c<4096; c++)
2364 value[len++] = '\0';
2369 ISO8859_1toUTF8(string, value + len, 4096 - len - 30);
2370 strcat(value, ") (ISO8859-1)");
2377 strcat(value, $"Empty string");
2381 strcat(value, $"Couldn't read memory");
2383 wh.value = CopyString(value);
2386 else if(wh.type && wh.type.kind == classType && wh.type._class &&
2387 wh.type._class.registered && wh.type._class.registered.type == enumClass)
2389 uint64 value = strtoul(exp.constant, null, 0);
2390 Class enumClass = eSystem_FindClass(GetPrivateModule(), wh.type._class.registered.name);
2391 EnumClassData enumeration = (EnumClassData)enumClass.data;
2393 for(item = enumeration.values.first; item; item = item.next)
2394 if((int)item.data == value)
2397 wh.value = CopyString(item.name);
2399 wh.value = CopyString($"Invalid Enum Value");
2400 result = (bool)atoi(exp.constant);
2402 else if(wh.type && (wh.type.kind == charType || (wh.type.kind == classType && wh.type._class &&
2403 wh.type._class.registered && !strcmp(wh.type._class.registered.fullName, "ecere::com::unichar"))) )
2410 if(exp.constant[0] == '\'')
2412 if((int)((byte *)exp.constant)[1] > 127)
2415 value = UTF8GetChar(exp.constant + 1, &nb);
2416 if(nb < 2) value = exp.constant[1];
2417 signedValue = value;
2421 signedValue = exp.constant[1];
2423 // Precomp Syntax error with boot strap here:
2424 byte b = (byte)(char)signedValue;
2425 value = (unichar) b;
2431 if(wh.type.kind == charType && wh.type.isSigned)
2433 signedValue = (int)(char)strtol(exp.constant, null, 0);
2435 // Precomp Syntax error with boot strap here:
2436 byte b = (byte)(char)signedValue;
2437 value = (unichar) b;
2442 value = strtoul(exp.constant, null, 0);
2443 signedValue = (int)value;
2447 UTF32toUTF8Len(&value, 1, charString, 5);
2449 sprintf(string, "\'\\0' (0)");
2450 else if(value == '\t')
2451 sprintf(string, "\'\\t' (%d)", value);
2452 else if(value == '\n')
2453 sprintf(string, "\'\\n' (%d)", value);
2454 else if(value == '\r')
2455 sprintf(string, "\'\\r' (%d)", value);
2456 else if(wh.type.kind == charType && wh.type.isSigned)
2457 sprintf(string, "\'%s\' (%d)", charString, signedValue);
2458 else if(value > 256 || wh.type.kind != charType)
2460 if(value > 0x10FFFF || !GetCharCategory(value))
2461 sprintf(string, $"Invalid Unicode Keypoint (0x%08X)", value);
2463 sprintf(string, "\'%s\' (U+%04X)", charString, value);
2466 sprintf(string, "\'%s\' (%d)", charString, value);
2468 wh.value = CopyString(string);
2473 wh.value = CopyString(exp.constant);
2474 result = (bool)atoi(exp.constant);
2480 wh.value = PrintHexUInt(exp.address);
2481 result = (bool)exp.address;
2485 char tempString[256];
2486 if(exp.member.memberType == propertyMember)
2487 sprintf(watchmsg, $"Missing property evaluation support for \"%s\"", wh.expression);
2489 sprintf(watchmsg, $"Evaluation failed for \"%s\" of type \"%s\"", wh.expression,
2490 exp.type.OnGetString(tempString, null, null));
2496 sprintf(watchmsg, $"Invalid expression: \"%s\"", wh.expression);
2497 if(exp) FreeExpression(exp);
2500 SetPrivateModule(backupPrivateModule);
2501 SetCurrentContext(backupContext);
2502 SetTopContext(backupContext);
2503 SetGlobalContext(backupContext);
2504 SetThisClass(backupThisClass);
2507 // wh.value = CopyString("No source file found for selected frame");
2510 wh.value = CopyString(watchmsg);
2512 ide.watchesView.UpdateWatch(wh);
2516 void EvaluateWatches()
2518 for(wh : ide.workspace.watches)
2522 char * ::GdbEvaluateExpression(char * expression)
2526 GdbCommand(false, "-data-evaluate-expression \"%s\"", expression);
2528 ide.outputView.debugBox.Logf("Debugger Error: GdbEvaluateExpression\n");
2532 // to be removed... use GdbReadMemory that returns a byte array instead
2533 char * ::GdbReadMemoryString(uint address, int size, char format, int rows, int cols)
2539 printf("GdbReadMemoryString called with size = 0!\n");
2541 GdbCommand(false, "-data-read-memory 0x%08x %c, %d, %d, %d", address, format, size, rows, cols);
2543 ide.outputView.debugBox.Logf("Debugger Error: GdbReadMemoryString\n");
2547 byte * ::GdbReadMemory(uint address, int bytes)
2551 GdbCommand(false, "-data-read-memory 0x%08x %c, 1, 1, %d", address, 'u', bytes);
2554 printf("GdbReadMemory called with bytes = 0!\n");
2557 ide.outputView.debugBox.Logf("Debugger Error: GdbReadMemory\n");
2558 else if(eval.result && strcmp(eval.result, "N/A"))
2560 byte * result = new byte[bytes];
2561 byte * string = eval.result;
2565 result[c++] = (byte)strtol(string, &string, 10);
2581 void EventHit(GdbDataStop stopItem)
2583 bool conditionMet = true;
2584 Breakpoint bp = bpHit;
2586 if(!bp && bpRunToCursor)
2590 GdbCommand(false, "-break-delete %d", bp.bp.number);
2595 if(bp.type == user && bp.line != stopItem.frame.line)
2597 bp.line = stopItem.frame.line;
2598 ide.breakpointsView.UpdateBreakpoint(bp.row);
2599 ide.workspace.Save();
2605 case internalWinMain:
2606 GdbBreakpointsInsert();
2607 if(userBreakOnInternBreak)
2609 userBreakOnInternBreak = false;
2610 // Why was SelectFrame missing here?
2611 SelectFrame(activeFrameLevel);
2612 GoToStackFrameLine(activeFrameLevel, true);
2613 //ide.AdjustDebugMenus();
2618 GdbExecContinue(false);
2620 case internalModulesLoaded:
2622 GdbBreakpointsInsert();
2623 GdbExecContinue(false);
2628 conditionMet = ResolveWatch(bp.condition);
2629 if(conditionMet && (bp.level == -1 || bp.level == frameCount))
2632 if(bp.hits > bp.ignore)
2634 ignoreBreakpoints = false;
2635 // Why was SelectFrame missing here?
2636 SelectFrame(activeFrameLevel);
2637 GoToStackFrameLine(activeFrameLevel, true);
2638 //ide.AdjustDebugMenus();
2641 if(bp.type == BreakpointType::runToCursor)
2643 delete bpRunToCursor;
2644 bpRunToCursor = null;
2650 ide.breakpointsView.UpdateBreakpoint(bp.row);*/
2651 GdbExecContinue(false);
2655 GdbExecContinue(false);
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();
2670 //ide.AdjustDebugMenus();
2674 serialSemaphore.Release();
2679 ide.outputView.debugBox.Logf($"Debugger Fatal Error: GDB lost\n");
2680 ide.outputView.debugBox.Logf($"Debugging stopped\n");
2683 //ChangeState(terminated);
2687 void GdbThreadMain(char * output)
2690 Array<char *> outTokens { minAllocSize = 50 };
2691 Array<char *> subTokens { minAllocSize = 50 };
2692 DebugListItem item { };
2693 DebugListItem item2 { };
2694 bool setWaitingForPID = false;
2696 #if defined(GDB_DEBUG_CONSOLE) || defined(GDB_DEBUG_GUI)
2697 #ifdef GDB_DEBUG_CONSOLE
2698 Log(output); Log("\n");
2700 #ifdef GDB_DEBUG_OUTPUT
2702 int len = strlen(output);
2710 for(c = 0; c < len / 1024; c++)
2712 strncpy(tmp, start, 1024);
2713 ide.outputView.gdbBox.Logf("out: %s\n", tmp);
2716 ide.outputView.gdbBox.Logf("out: %s\n", start);
2720 ide.outputView.gdbBox.Logf("out: %s\n", output);
2724 #ifdef GDB_DEBUG_CONSOLE
2725 strcpy(lastGdbOutput, output);
2727 #ifdef GDB_DEBUG_GUI
2728 if(ide.gdbDialog) ide.gdbDialog.AddOutput(output);
2735 if(strstr(output, "No debugging symbols found") || strstr(output, "(no debugging symbols found)"))
2738 ide.outputView.debugBox.Logf($"Target doesn't contain debug information!\n");
2744 if(TokenizeList(output, ',', outTokens) && !strcmp(outTokens[0], "^done"))
2746 //if(outTokens.count == 1)
2751 ChangeState(loaded);
2752 targetProcessId = 0;
2753 if(outTokens.count > 1 && TokenizeListItem(outTokens[1], item))
2755 if(!strcmp(item.name, "reason"))
2757 char * reason = item.value;
2758 StripQuotes(reason, reason);
2759 if(!strcmp(reason, "exited-normally") || !strcmp(reason, "exited") || !strcmp(reason, "exited-signalled"))
2762 if(outTokens.count > 2 && TokenizeListItem(outTokens[2], item2))
2764 StripQuotes(item2.value, item2.value);
2765 if(!strcmp(item2.name, "exit-code"))
2766 exitCode = item2.value;
2772 HandleExit(reason, exitCode);
2776 DebuggerProtocolUnknown("Unknown kill reply", item.name);
2779 HandleExit(null, null);
2782 if(outTokens.count > 1 && TokenizeListItem(outTokens[1], item))
2784 if(!strcmp(item.name, "bkpt"))
2786 sentBreakInsert = false;
2789 printf("problem\n");
2791 bpItem = GdbDataBreakpoint { };
2792 item.value = StripCurlies(item.value);
2793 TokenizeList(item.value, ',', subTokens);
2794 for(i = 0; i < subTokens.count; i++)
2796 if(TokenizeListItem(subTokens[i], item))
2798 StripQuotes(item.value, item.value);
2799 if(!strcmp(item.name, "number"))
2800 bpItem.number = atoi(item.value);
2801 else if(!strcmp(item.name, "type"))
2802 bpItem.type = CopyString(item.value);
2803 else if(!strcmp(item.name, "disp"))
2804 bpItem.disp = CopyString(item.value);
2805 else if(!strcmp(item.name, "enabled"))
2806 bpItem.enabled = (!strcmpi(item.value, "y"));
2807 else if(!strcmp(item.name, "addr"))
2808 bpItem.addr = CopyString(item.value);
2809 else if(!strcmp(item.name, "func"))
2810 bpItem.func = CopyString(item.value);
2811 else if(!strcmp(item.name, "file"))
2812 bpItem.file = item.value;
2813 else if(!strcmp(item.name, "line"))
2814 bpItem.line = atoi(item.value);
2815 else if(!strcmp(item.name, "at"))
2816 bpItem.at = CopyString(item.value);
2817 else if(!strcmp(item.name, "times"))
2818 bpItem.times = atoi(item.value);
2821 //breakType = bpValidation;
2822 //app.SignalEvent();
2823 subTokens.RemoveAll();
2825 else if(!strcmp(item.name, "BreakpointTable"))
2826 ide.outputView.debugBox.Logf("Debugger Error: Command reply BreakpointTable not handled\n");
2827 else if(!strcmp(item.name, "depth"))
2829 StripQuotes(item.value, item.value);
2830 frameCount = atoi(item.value);
2832 stackFrames.Free(Frame::Free);
2834 else if(!strcmp(item.name, "stack"))
2837 if(stackFrames.count)
2838 ide.callStackView.Logf("...\n");
2841 item.value = StripBrackets(item.value);
2842 TokenizeList(item.value, ',', subTokens);
2843 for(i = 0; i < subTokens.count; i++)
2845 if(TokenizeListItem(subTokens[i], item))
2847 if(!strcmp(item.name, "frame"))
2850 stackFrames.Add(frame);
2851 item.value = StripCurlies(item.value);
2852 ParseFrame(frame, item.value);
2853 if(frame.file && frame.from)
2854 DebuggerProtocolUnknown("Unexpected frame file and from members present", "");
2858 if(activeFrameLevel == -1)
2860 if(ide.projectView.IsModuleInProject(frame.file));
2862 if(frame.level != 0)
2864 //stopItem.frame = frame;
2865 breakType = selectFrame;
2868 activeFrame = frame;
2869 activeFrameLevel = frame.level;
2872 ide.callStackView.Logf("%3d ", frame.level);
2873 if(!strncmp(frame.func, "__ecereMethod_", strlen("__ecereMethod_")))
2874 ide.callStackView.Logf($"%s Method, %s:%d\n", &frame.func[strlen("__ecereMethod_")], (s = CopySystemPath(frame.file)), frame.line);
2875 else if(!strncmp(frame.func, "__ecereProp_", strlen("__ecereProp_")))
2876 ide.callStackView.Logf($"%s Property, %s:%d\n", &frame.func[strlen("__ecereProp_")], (s = CopySystemPath(frame.file)), frame.line);
2877 else if(!strncmp(frame.func, "__ecereConstructor_", strlen("__ecereConstructor_")))
2878 ide.callStackView.Logf($"%s Constructor, %s:%d\n", &frame.func[strlen("__ecereConstructor_")], (s = CopySystemPath(frame.file)), frame.line);
2879 else if(!strncmp(frame.func, "__ecereDestructor_", strlen("__ecereDestructor_")))
2880 ide.callStackView.Logf($"%s Destructor, %s:%d\n", &frame.func[strlen("__ecereDestructor_")], (s = CopySystemPath(frame.file)), frame.line);
2882 ide.callStackView.Logf($"%s Function, %s:%d\n", frame.func, (s = CopySystemPath(frame.file)), frame.line);
2887 ide.callStackView.Logf("%3d ", frame.level);
2892 ide.callStackView.Logf($"inside %s, %s\n", frame.func, (s = CopySystemPath(frame.from)));
2896 ide.callStackView.Logf("%s\n", frame.func);
2898 ide.callStackView.Logf($"unknown source\n");
2902 DebuggerProtocolUnknown("Unknown stack content", item.name);
2905 if(activeFrameLevel == -1)
2907 activeFrameLevel = 0;
2908 activeFrame = stackFrames.first;
2910 ide.callStackView.Home();
2912 subTokens.RemoveAll();
2914 /*else if(!strcmp(item.name, "frame"))
2917 item.value = StripCurlies(item.value);
2918 ParseFrame(&frame, item.value);
2920 else if(!strcmp(item.name, "thread-ids"))
2922 ide.threadsView.Clear();
2923 item.value = StripCurlies(item.value);
2924 TokenizeList(item.value, ',', subTokens);
2925 for(i = subTokens.count - 1; ; i--)
2927 if(TokenizeListItem(subTokens[i], item))
2929 if(!strcmp(item.name, "thread-id"))
2932 StripQuotes(item.value, item.value);
2933 value = atoi(item.value);
2934 ide.threadsView.Logf("%3d \n", value);
2937 DebuggerProtocolUnknown("Unknown threads content", item.name);
2942 ide.threadsView.Home();
2944 subTokens.RemoveAll();
2945 //if(!strcmp(outTokens[2], "number-of-threads"))
2947 else if(!strcmp(item.name, "new-thread-id"))
2949 StripQuotes(item.value, item.value);
2950 activeThread = atoi(item.value);
2952 else if(!strcmp(item.name, "value"))
2954 StripQuotes(item.value, item.value);
2955 eval.result = CopyString(item.value);
2956 eval.active = false;
2958 else if(!strcmp(item.name, "addr"))
2960 for(i = 2; i < outTokens.count; i++)
2962 if(TokenizeListItem(outTokens[i], item))
2964 if(!strcmp(item.name, "total-bytes"))
2966 StripQuotes(item.value, item.value);
2967 eval.bytes = atoi(item.value);
2969 else if(!strcmp(item.name, "next-row"))
2971 StripQuotes(item.value, item.value);
2972 eval.nextBlockAddress = strtoul(item.value, null, 0);
2974 else if(!strcmp(item.name, "memory"))
2978 //StripQuotes(item.value, item.value);
2979 item.value = StripBrackets(item.value);
2980 // this should be treated as a list...
2981 item.value = StripCurlies(item.value);
2982 TokenizeList(item.value, ',', subTokens);
2983 for(j = 0; j < subTokens.count; j++)
2985 if(TokenizeListItem(subTokens[j], item))
2987 if(!strcmp(item.name, "data"))
2989 item.value = StripBrackets(item.value);
2990 StripQuotes2(item.value, item.value);
2991 eval.result = CopyString(item.value);
2992 eval.active = false;
2996 subTokens.RemoveAll();
3001 else if(!strcmp(item.name, "source-path"))
3005 DebuggerProtocolUnknown("Unknown command reply", item.name);
3008 else if(!strcmp(outTokens[0], "^running"))
3010 waitingForPID = true;
3011 setWaitingForPID = true;
3013 else if(!strcmp(outTokens[0], "^exit"))
3015 ChangeState(terminated);
3016 //ide.AdjustDebugMenus();
3017 // ide.outputView.debugBox.Logf("Exit\n");
3020 serialSemaphore.Release();
3022 else if(!strcmp(outTokens[0], "^error"))
3026 sentBreakInsert = false;
3029 printf("problem\n");
3031 bpItem = GdbDataBreakpoint { };
3034 if(outTokens.count > 1 && TokenizeListItem(outTokens[1], item))
3036 if(!strcmp(item.name, "msg"))
3038 StripQuotes(item.value, item.value);
3041 eval.active = false;
3043 if(strstr(item.value, "No symbol") && strstr(item.value, "in current context"))
3044 eval.error = symbolNotFound;
3045 else if(strstr(item.value, "Cannot access memory at address"))
3046 eval.error = memoryCantBeRead;
3048 eval.error = unknown;
3050 else if(!strcmp(item.value, "Previous frame inner to this frame (corrupt stack?)"))
3053 else if(!strncmp(item.value, "Cannot access memory at address", 31))
3056 else if(!strcmp(item.value, "Cannot find bounds of current function"))
3058 ChangeState(stopped);
3059 gdbHandle.Printf("-exec-continue\n");
3061 else if(!strcmp(item.value, "ptrace: No such process."))
3063 ChangeState(loaded);
3064 targetProcessId = 0;
3065 //ide.AdjustDebugMenus();
3067 else if(!strcmp(item.value, "Function \\\"WinMain\\\" not defined."))
3070 else if(!strcmp(item.value, "You can't do that without a process to debug."))
3072 ChangeState(loaded);
3073 targetProcessId = 0;
3074 //ide.AdjustDebugMenus();
3076 else if(strstr(item.value, "No such file or directory."))
3078 ChangeState(loaded);
3079 targetProcessId = 0;
3080 //ide.AdjustDebugMenus();
3082 else if(strstr(item.value, "During startup program exited with code "))
3084 ChangeState(loaded);
3085 targetProcessId = 0;
3086 //ide.AdjustDebugMenus();
3091 if(strlen(item.value) < MAX_F_STRING)
3094 ide.outputView.debugBox.Logf("GDB: %s\n", (s = CopyUnescapedString(item.value)));
3098 ide.outputView.debugBox.Logf("GDB: %s\n", item.value);
3104 DebuggerProtocolUnknown("Unknown error content", item.name);
3107 DebuggerProtocolUnknown("Unknown result-record", outTokens[0]);
3109 outTokens.RemoveAll();
3112 DebuggerProtocolUnknown("Unknown status-async-output", outTokens[0]);
3115 if(TokenizeList(output, ',', outTokens) && !strcmp(outTokens[0], "=thread-group-created")) //=thread-group-created,id="7611"
3117 else if(!strcmp(outTokens[0], "=thread-created")) //=thread-created,id="1",group-id="7611"
3119 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"
3122 DebuggerProtocolUnknown("Unknown notify-async-output", outTokens[0]);
3123 outTokens.RemoveAll();
3127 if(TokenizeList(output, ',', outTokens))
3129 if(!strcmp(outTokens[0],"*running"))
3131 waitingForPID = true;
3132 setWaitingForPID = true;
3134 else if(!strcmp(outTokens[0], "*stopped"))
3136 ChangeState(stopped);
3138 if(outTokens.count > 1 && TokenizeListItem(outTokens[1], item))
3140 if(!strcmp(item.name, "reason"))
3142 char * reason = item.value;
3143 StripQuotes(reason, reason);
3144 if(!strcmp(reason, "exited-normally") || !strcmp(reason, "exited") || !strcmp(reason, "exited-signalled"))
3147 if(outTokens.count > 2 && TokenizeListItem(outTokens[2], item2))
3149 StripQuotes(item2.value, item2.value);
3150 if(!strcmp(item2.name, "exit-code"))
3151 exitCode = item2.value;
3157 HandleExit(reason, exitCode);
3159 else if(!strcmp(reason, "breakpoint-hit"))
3163 printf("problem\n");
3165 stopItem = GdbDataStop { };
3167 for(i = 2; i < outTokens.count; i++)
3169 TokenizeListItem(outTokens[i], item);
3170 StripQuotes(item.value, item.value);
3171 if(!strcmp(item.name, "bkptno"))
3172 stopItem.bkptno = atoi(item.value);
3173 else if(!strcmp(item.name, "thread-id"))
3174 stopItem.threadid = atoi(item.value);
3175 else if(!strcmp(item.name, "frame"))
3177 item.value = StripCurlies(item.value);
3178 ParseFrame(stopItem.frame, item.value);
3181 DebuggerProtocolUnknown("Unknown breakpoint hit item name", item.name);
3186 else if(!strcmp(reason, "end-stepping-range"))
3190 printf("problem\n");
3192 stopItem = GdbDataStop { };
3194 for(i = 2; i < outTokens.count; i++)
3196 TokenizeListItem(outTokens[i], item);
3197 StripQuotes(item.value, item.value);
3198 if(!strcmp(item.name, "thread-id"))
3199 stopItem.threadid = atoi(item.value);
3200 else if(!strcmp(item.name, "frame"))
3202 item.value = StripCurlies(item.value);
3203 ParseFrame(stopItem.frame, item.value);
3205 else if(!strcmp(item.name, "reason"))
3207 else if(!strcmp(item.name, "bkptno"))
3210 DebuggerProtocolUnknown("Unknown end of stepping range item name", item.name);
3214 //ide.AdjustDebugMenus();
3217 else if(!strcmp(reason, "function-finished"))
3221 printf("problem\n");
3223 stopItem = GdbDataStop { };
3224 stopItem.reason = CopyString(reason);
3226 for(i = 2; i < outTokens.count; i++)
3228 TokenizeListItem(outTokens[i], item);
3229 StripQuotes(item.value, item.value);
3230 if(!strcmp(item.name, "thread-id"))
3231 stopItem.threadid = atoi(item.value);
3232 else if(!strcmp(item.name, "frame"))
3234 item.value = StripCurlies(item.value);
3235 ParseFrame(stopItem.frame, item.value);
3237 else if(!strcmp(item.name, "gdb-result-var"))
3238 stopItem.gdbResultVar = CopyString(item.value);
3239 else if(!strcmp(item.name, "return-value"))
3240 stopItem.returnValue = CopyString(item.value);
3242 DebuggerProtocolUnknown("Unknown function finished item name", item.name);
3245 event = functionEnd;
3246 //ide.AdjustDebugMenus();
3249 else if(!strcmp(reason, "signal-received"))
3253 printf("problem\n");
3255 stopItem = GdbDataStop { };
3256 stopItem.reason = CopyString(reason);
3258 for(i = 2; i < outTokens.count; i++)
3260 TokenizeListItem(outTokens[i], item);
3261 StripQuotes(item.value, item.value);
3262 if(!strcmp(item.name, "signal-name"))
3263 stopItem.name = CopyString(item.value);
3264 else if(!strcmp(item.name, "signal-meaning"))
3265 stopItem.meaning = CopyString(item.value);
3266 else if(!strcmp(item.name, "thread-id"))
3267 stopItem.threadid = atoi(item.value);
3268 else if(!strcmp(item.name, "frame"))
3270 item.value = StripCurlies(item.value);
3271 ParseFrame(stopItem.frame, item.value);
3274 DebuggerProtocolUnknown("Unknown signal reveived item name", item.name);
3276 if(!strcmp(stopItem.name, "SIGTRAP"))
3288 //ide.AdjustDebugMenus(); ide.Update(null);
3294 //ide.AdjustDebugMenus(); ide.Update(null);
3297 else if(!strcmp(reason, "watchpoint-trigger"))
3298 DebuggerProtocolUnknown("Reason watchpoint trigger not handled", "");
3299 else if(!strcmp(reason, "read-watchpoint-trigger"))
3300 DebuggerProtocolUnknown("Reason read watchpoint trigger not handled", "");
3301 else if(!strcmp(reason, "access-watchpoint-trigger"))
3302 DebuggerProtocolUnknown("Reason access watchpoint trigger not handled", "");
3303 else if(!strcmp(reason, "watchpoint-scope"))
3304 DebuggerProtocolUnknown("Reason watchpoint scope not handled", "");
3305 else if(!strcmp(reason, "location-reached"))
3306 DebuggerProtocolUnknown("Reason location reached not handled", "");
3308 DebuggerProtocolUnknown("Unknown reason", reason);
3315 DebuggerProtocolUnknown("Unknown exec-async-output", outTokens[0]);
3316 outTokens.RemoveAll();
3319 if(!strcmpi(output, "(gdb) "))
3323 char exeFile[MAX_LOCATION];
3324 int oldProcessID = targetProcessId;
3325 GetLastDirectory(targetFile, exeFile);
3329 targetProcessId = Process_GetChildExeProcessId(gdbProcessId, exeFile);
3330 if(targetProcessId || gdbHandle.Peek()) break;
3336 ChangeState(running);
3337 //ide.AdjustDebugMenus(); ide.Update(null);
3339 else if(!oldProcessID)
3341 ide.outputView.debugBox.Logf($"Debugger Error: No target process ID\n");
3342 // TO VERIFY: The rest of this block has not been thoroughly tested in this particular location
3343 gdbHandle.Printf("-gdb-exit\n");
3345 ChangeState(terminated); //loaded;
3350 for(bp : ide.workspace.breakpoints)
3351 bp.inserted = false;
3354 bp.inserted = false;
3356 bpRunToCursor.inserted = false;
3358 ide.outputView.debugBox.Logf($"Debugging stopped\n");
3359 ClearBreakDisplay();
3360 //ide.AdjustDebugMenus(); ide.Update(null);
3362 #if defined(__unix__)
3363 if(FileExists(progFifoPath)) //fileCreated)
3365 progThread.terminate = true;
3368 fifoFile.CloseInput();
3375 DeleteFile(progFifoPath);
3376 progFifoPath[0] = '\0';
3383 serialSemaphore.Release();
3386 DebuggerProtocolUnknown($"Unknown prompt", output);
3390 if(!strncmp(output, "&\"warning:", 10))
3393 content = strstr(output, "\"");
3394 StripQuotes(content, content);
3395 content = strstr(content, ":");
3401 ide.outputView.debugBox.LogRaw((s = CopyUnescapedString(content)));
3408 DebuggerProtocolUnknown($"Unknown output", output);
3410 if(!setWaitingForPID)
3411 waitingForPID = false;
3412 setWaitingForPID = false;
3420 void RunToCursorPrepare(char * absoluteFilePath, char * relativeFilePath, int lineNumber)
3424 //bpRunToCursor.Free();
3425 bpRunToCursor = Breakpoint { };
3428 bpRunToCursor = Breakpoint { };
3430 if(absoluteFilePath)
3431 bpRunToCursor.absoluteFilePath = CopyString(absoluteFilePath);
3432 if(relativeFilePath)
3433 bpRunToCursor.relativeFilePath = CopyString(relativeFilePath);
3434 bpRunToCursor.line = lineNumber;
3435 bpRunToCursor.type = runToCursor;
3436 bpRunToCursor.enabled = true;
3437 bpRunToCursor.condition = null;
3438 bpRunToCursor.ignore = 0;
3439 bpRunToCursor.level = -1;
3442 ExpressionType ::DebugEvalExpTypeError(char * result)
3448 case symbolNotFound:
3449 return symbolErrorExp;
3450 case memoryCantBeRead:
3451 return memoryErrorExp;
3453 return unknownErrorExp;
3456 char * ::EvaluateExpression(char * expression, ExpressionType * error)
3459 if(ide.projectView && ide.debugger.state == stopped)
3461 result = GdbEvaluateExpression(expression);
3462 *error = DebugEvalExpTypeError(result);
3467 *error = noDebuggerErrorExp;
3472 char * ::ReadMemory(uint address, int size, char format, ExpressionType * error)
3475 char * result = GdbReadMemoryString(address, size, format, 1, 1);
3476 if(!result || !strcmp(result, "N/A"))
3477 *error = memoryErrorExp;
3479 *error = DebugEvalExpTypeError(result);
3484 class GdbThread : Thread
3490 static char output[4096];
3491 Array<char> dynamicBuffer { minAllocSize = 4096 };
3492 DualPipe oldGdbHandle = gdbHandle;
3493 incref oldGdbHandle;
3496 while(debugger.state != terminated && gdbHandle && !gdbHandle.Eof())
3500 result = gdbHandle.Read(output, 1, sizeof(output));
3501 if(debugger.state == terminated || !gdbHandle || gdbHandle.Eof())
3509 for(c = 0; c<result; c++)
3511 if(output[c] == '\n')
3513 int pos = dynamicBuffer.size;
3514 dynamicBuffer.size += c - start;
3515 memcpy(&dynamicBuffer[pos], output + start, c - start);
3516 if(dynamicBuffer.count && dynamicBuffer[dynamicBuffer.count - 1] != '\r')
3517 // COMMENTED OUT DUE TO ISSUE #135, FIXED
3518 //if(dynamicBuffer.array[dynamicBuffer.count - 1] != '\r')
3519 dynamicBuffer.size++;
3520 dynamicBuffer[dynamicBuffer.count - 1] = '\0';
3522 // printf("%s\n", dynamicBuffer.array);
3524 debugger.GdbThreadMain(&dynamicBuffer[0]);
3525 dynamicBuffer.size = 0;
3531 int pos = dynamicBuffer.size;
3532 dynamicBuffer.size += c - start;
3533 memcpy(&dynamicBuffer[pos], output + start, c - start);
3539 printf("Got end of file from GDB!\n");
3543 delete dynamicBuffer;
3544 //if(oldGdbHandle == gdbHandle)
3545 debugger.GdbThreadExit();
3546 delete oldGdbHandle;
3552 #if defined(__unix__)
3557 #include <sys/types.h>
3562 class ProgramThread : Thread
3568 bool fileCreated = false;
3570 static char output[1000];
3573 /*if(!mkfifo(progFifoPath, mask))
3580 ide.outputView.debugBox.Logf($"err: Unable to create FIFO %s\n", progFifoPath);
3584 if(FileExists(progFifoPath)) //fileCreated)
3586 fifoFile = FileOpen(progFifoPath, read);
3590 ide.outputView.debugBox.Logf($"err: Unable to open FIFO %s for read\n", progFifoPath);
3599 fd = fileno(fifoFile.input);
3601 //fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
3605 while(!terminate && fifoFile && !fifoFile.Eof())
3608 struct timeval time;
3616 selectResult = select(fd + 1, &rs, null, null, &time);
3617 if(FD_ISSET(fd, &rs))
3619 int result = read(fd, output, sizeof(output)-1);
3620 if(!result || (result < 0 && errno != EAGAIN))
3624 output[result] = '\0';
3625 if(strcmp(output,"&\"warning: GDB: Failed to set controlling terminal: Invalid argument\\n\"\n"))
3628 ide.outputView.debugBox.Log(output);
3637 //fifoFile.CloseInput();
3640 ide.outputView.debugBox.Log("\n");
3644 if(FileExists(progFifoPath)) //fileCreated)
3646 DeleteFile(progFifoPath);
3647 progFifoPath[0] = '\0';
3655 class Argument : struct
3657 Argument prev, next;
3673 class Frame : struct
3682 property char * from { set { delete from; if(value) from = CopyUnescapedUnixPath(value); } }
3684 property char * file { set { delete file; if(value) file = CopyUnescapedUnixPath(value); } }
3685 char * absoluteFile;
3694 delete absoluteFile;
3695 args.Free(Argument::Free);
3704 class GdbDataStop : struct
3721 char * gdbResultVar;
3731 if(!strcmp(reason, "signal-received"))
3736 else if(!strcmp(reason, "function-finished"))
3738 delete gdbResultVar;
3743 if(frame) frame.Free();
3752 class GdbDataBreakpoint : struct
3761 property char * file { set { delete file; if(value) file = CopyUnescapedUnixPath(value); } }
3776 ~GdbDataBreakpoint()
3782 class Breakpoint : struct
3786 char * relativeFilePath;
3787 char * absoluteFilePath;
3795 BreakpointType type;
3798 GdbDataBreakpoint bp;
3800 char * LocationToString()
3802 char location[MAX_LOCATION+20];
3803 sprintf(location, "%s:%d", relativeFilePath, line);
3804 #if defined(__WIN32__)
3805 ChangeCh(location, '/', '\\');
3807 return CopyString(location);
3812 if(relativeFilePath && relativeFilePath[0])
3814 f.Printf(" * %d,%d,%d,%d,%s\n", enabled ? 1 : 0, ignore, level, line, relativeFilePath);
3816 f.Printf(" ~ %s\n", condition.expression);
3825 delete relativeFilePath;
3826 delete absoluteFilePath;
3836 class Watch : struct
3847 f.Printf(" ~ %s\n", expression);
3871 class DebugListItem : struct
3877 struct DebugEvaluationData
3882 uint nextBlockAddress;
3884 DebuggerEvaluationError error;
3887 class CodeLocation : struct
3890 char * absoluteFile;
3893 CodeLocation ::ParseCodeLocation(char * location)
3897 char * colon = null;
3899 char loc[MAX_LOCATION];
3900 strcpy(loc, location);
3901 for(temp = loc; temp = strstr(temp, ":"); temp++)
3909 int line = atoi(colon);
3912 CodeLocation codloc { line = line };
3913 codloc.file = CopyString(loc);
3914 codloc.absoluteFile = ide.workspace.GetAbsolutePathFromRelative(loc);
3926 delete absoluteFile;