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 ide.breakpointsView.UpdateBreakpoint(bp.row);
2633 if(bp.hits > bp.ignore)
2635 ignoreBreakpoints = false;
2636 // Why was SelectFrame missing here?
2637 SelectFrame(activeFrameLevel);
2638 GoToStackFrameLine(activeFrameLevel, true);
2639 //ide.AdjustDebugMenus();
2642 if(bp.type == BreakpointType::runToCursor)
2644 delete bpRunToCursor;
2645 bpRunToCursor = null;
2651 ide.breakpointsView.UpdateBreakpoint(bp.row);*/
2652 GdbExecContinue(false);
2656 GdbExecContinue(false);
2661 ide.outputView.debugBox.Logf("Debugger Error: Breakpoint hit could not match breakpoint instance\n");
2664 void GdbThreadExit()
2666 if(state != terminated)
2668 ChangeState(terminated);
2669 targetProcessId = 0;
2670 ClearBreakDisplay();
2671 //ide.AdjustDebugMenus();
2675 serialSemaphore.Release();
2680 ide.outputView.debugBox.Logf($"Debugger Fatal Error: GDB lost\n");
2681 ide.outputView.debugBox.Logf($"Debugging stopped\n");
2684 //ChangeState(terminated);
2688 void GdbThreadMain(char * output)
2691 Array<char *> outTokens { minAllocSize = 50 };
2692 Array<char *> subTokens { minAllocSize = 50 };
2693 DebugListItem item { };
2694 DebugListItem item2 { };
2695 bool setWaitingForPID = false;
2697 #if defined(GDB_DEBUG_CONSOLE) || defined(GDB_DEBUG_GUI)
2698 #ifdef GDB_DEBUG_CONSOLE
2699 Log(output); Log("\n");
2701 #ifdef GDB_DEBUG_OUTPUT
2703 int len = strlen(output);
2711 for(c = 0; c < len / 1024; c++)
2713 strncpy(tmp, start, 1024);
2714 ide.outputView.gdbBox.Logf("out: %s\n", tmp);
2717 ide.outputView.gdbBox.Logf("out: %s\n", start);
2721 ide.outputView.gdbBox.Logf("out: %s\n", output);
2725 #ifdef GDB_DEBUG_CONSOLE
2726 strcpy(lastGdbOutput, output);
2728 #ifdef GDB_DEBUG_GUI
2729 if(ide.gdbDialog) ide.gdbDialog.AddOutput(output);
2736 if(strstr(output, "No debugging symbols found") || strstr(output, "(no debugging symbols found)"))
2739 ide.outputView.debugBox.Logf($"Target doesn't contain debug information!\n");
2745 if(TokenizeList(output, ',', outTokens) && !strcmp(outTokens[0], "^done"))
2747 //if(outTokens.count == 1)
2752 ChangeState(loaded);
2753 targetProcessId = 0;
2754 if(outTokens.count > 1 && TokenizeListItem(outTokens[1], item))
2756 if(!strcmp(item.name, "reason"))
2758 char * reason = item.value;
2759 StripQuotes(reason, reason);
2760 if(!strcmp(reason, "exited-normally") || !strcmp(reason, "exited") || !strcmp(reason, "exited-signalled"))
2763 if(outTokens.count > 2 && TokenizeListItem(outTokens[2], item2))
2765 StripQuotes(item2.value, item2.value);
2766 if(!strcmp(item2.name, "exit-code"))
2767 exitCode = item2.value;
2773 HandleExit(reason, exitCode);
2777 DebuggerProtocolUnknown("Unknown kill reply", item.name);
2780 HandleExit(null, null);
2783 if(outTokens.count > 1 && TokenizeListItem(outTokens[1], item))
2785 if(!strcmp(item.name, "bkpt"))
2787 sentBreakInsert = false;
2790 printf("problem\n");
2792 bpItem = GdbDataBreakpoint { };
2793 item.value = StripCurlies(item.value);
2794 TokenizeList(item.value, ',', subTokens);
2795 for(i = 0; i < subTokens.count; i++)
2797 if(TokenizeListItem(subTokens[i], item))
2799 StripQuotes(item.value, item.value);
2800 if(!strcmp(item.name, "number"))
2801 bpItem.number = atoi(item.value);
2802 else if(!strcmp(item.name, "type"))
2803 bpItem.type = CopyString(item.value);
2804 else if(!strcmp(item.name, "disp"))
2805 bpItem.disp = CopyString(item.value);
2806 else if(!strcmp(item.name, "enabled"))
2807 bpItem.enabled = (!strcmpi(item.value, "y"));
2808 else if(!strcmp(item.name, "addr"))
2809 bpItem.addr = CopyString(item.value);
2810 else if(!strcmp(item.name, "func"))
2811 bpItem.func = CopyString(item.value);
2812 else if(!strcmp(item.name, "file"))
2813 bpItem.file = item.value;
2814 else if(!strcmp(item.name, "line"))
2815 bpItem.line = atoi(item.value);
2816 else if(!strcmp(item.name, "at"))
2817 bpItem.at = CopyString(item.value);
2818 else if(!strcmp(item.name, "times"))
2819 bpItem.times = atoi(item.value);
2822 //breakType = bpValidation;
2823 //app.SignalEvent();
2824 subTokens.RemoveAll();
2826 else if(!strcmp(item.name, "BreakpointTable"))
2827 ide.outputView.debugBox.Logf("Debugger Error: Command reply BreakpointTable not handled\n");
2828 else if(!strcmp(item.name, "depth"))
2830 StripQuotes(item.value, item.value);
2831 frameCount = atoi(item.value);
2833 stackFrames.Free(Frame::Free);
2835 else if(!strcmp(item.name, "stack"))
2838 if(stackFrames.count)
2839 ide.callStackView.Logf("...\n");
2842 item.value = StripBrackets(item.value);
2843 TokenizeList(item.value, ',', subTokens);
2844 for(i = 0; i < subTokens.count; i++)
2846 if(TokenizeListItem(subTokens[i], item))
2848 if(!strcmp(item.name, "frame"))
2851 stackFrames.Add(frame);
2852 item.value = StripCurlies(item.value);
2853 ParseFrame(frame, item.value);
2854 if(frame.file && frame.from)
2855 DebuggerProtocolUnknown("Unexpected frame file and from members present", "");
2859 if(activeFrameLevel == -1)
2861 if(ide.projectView.IsModuleInProject(frame.file));
2863 if(frame.level != 0)
2865 //stopItem.frame = frame;
2866 breakType = selectFrame;
2869 activeFrame = frame;
2870 activeFrameLevel = frame.level;
2873 ide.callStackView.Logf("%3d ", frame.level);
2874 if(!strncmp(frame.func, "__ecereMethod_", strlen("__ecereMethod_")))
2875 ide.callStackView.Logf($"%s Method, %s:%d\n", &frame.func[strlen("__ecereMethod_")], (s = CopySystemPath(frame.file)), frame.line);
2876 else if(!strncmp(frame.func, "__ecereProp_", strlen("__ecereProp_")))
2877 ide.callStackView.Logf($"%s Property, %s:%d\n", &frame.func[strlen("__ecereProp_")], (s = CopySystemPath(frame.file)), frame.line);
2878 else if(!strncmp(frame.func, "__ecereConstructor_", strlen("__ecereConstructor_")))
2879 ide.callStackView.Logf($"%s Constructor, %s:%d\n", &frame.func[strlen("__ecereConstructor_")], (s = CopySystemPath(frame.file)), frame.line);
2880 else if(!strncmp(frame.func, "__ecereDestructor_", strlen("__ecereDestructor_")))
2881 ide.callStackView.Logf($"%s Destructor, %s:%d\n", &frame.func[strlen("__ecereDestructor_")], (s = CopySystemPath(frame.file)), frame.line);
2883 ide.callStackView.Logf($"%s Function, %s:%d\n", frame.func, (s = CopySystemPath(frame.file)), frame.line);
2888 ide.callStackView.Logf("%3d ", frame.level);
2893 ide.callStackView.Logf($"inside %s, %s\n", frame.func, (s = CopySystemPath(frame.from)));
2897 ide.callStackView.Logf("%s\n", frame.func);
2899 ide.callStackView.Logf($"unknown source\n");
2903 DebuggerProtocolUnknown("Unknown stack content", item.name);
2906 if(activeFrameLevel == -1)
2908 activeFrameLevel = 0;
2909 activeFrame = stackFrames.first;
2911 ide.callStackView.Home();
2913 subTokens.RemoveAll();
2915 /*else if(!strcmp(item.name, "frame"))
2918 item.value = StripCurlies(item.value);
2919 ParseFrame(&frame, item.value);
2921 else if(!strcmp(item.name, "thread-ids"))
2923 ide.threadsView.Clear();
2924 item.value = StripCurlies(item.value);
2925 TokenizeList(item.value, ',', subTokens);
2926 for(i = subTokens.count - 1; ; i--)
2928 if(TokenizeListItem(subTokens[i], item))
2930 if(!strcmp(item.name, "thread-id"))
2933 StripQuotes(item.value, item.value);
2934 value = atoi(item.value);
2935 ide.threadsView.Logf("%3d \n", value);
2938 DebuggerProtocolUnknown("Unknown threads content", item.name);
2943 ide.threadsView.Home();
2945 subTokens.RemoveAll();
2946 //if(!strcmp(outTokens[2], "number-of-threads"))
2948 else if(!strcmp(item.name, "new-thread-id"))
2950 StripQuotes(item.value, item.value);
2951 activeThread = atoi(item.value);
2953 else if(!strcmp(item.name, "value"))
2955 StripQuotes(item.value, item.value);
2956 eval.result = CopyString(item.value);
2957 eval.active = false;
2959 else if(!strcmp(item.name, "addr"))
2961 for(i = 2; i < outTokens.count; i++)
2963 if(TokenizeListItem(outTokens[i], item))
2965 if(!strcmp(item.name, "total-bytes"))
2967 StripQuotes(item.value, item.value);
2968 eval.bytes = atoi(item.value);
2970 else if(!strcmp(item.name, "next-row"))
2972 StripQuotes(item.value, item.value);
2973 eval.nextBlockAddress = strtoul(item.value, null, 0);
2975 else if(!strcmp(item.name, "memory"))
2979 //StripQuotes(item.value, item.value);
2980 item.value = StripBrackets(item.value);
2981 // this should be treated as a list...
2982 item.value = StripCurlies(item.value);
2983 TokenizeList(item.value, ',', subTokens);
2984 for(j = 0; j < subTokens.count; j++)
2986 if(TokenizeListItem(subTokens[j], item))
2988 if(!strcmp(item.name, "data"))
2990 item.value = StripBrackets(item.value);
2991 StripQuotes2(item.value, item.value);
2992 eval.result = CopyString(item.value);
2993 eval.active = false;
2997 subTokens.RemoveAll();
3002 else if(!strcmp(item.name, "source-path"))
3006 DebuggerProtocolUnknown("Unknown command reply", item.name);
3009 else if(!strcmp(outTokens[0], "^running"))
3011 waitingForPID = true;
3012 setWaitingForPID = true;
3014 else if(!strcmp(outTokens[0], "^exit"))
3016 ChangeState(terminated);
3017 //ide.AdjustDebugMenus();
3018 // ide.outputView.debugBox.Logf("Exit\n");
3021 serialSemaphore.Release();
3023 else if(!strcmp(outTokens[0], "^error"))
3027 sentBreakInsert = false;
3030 printf("problem\n");
3032 bpItem = GdbDataBreakpoint { };
3035 if(outTokens.count > 1 && TokenizeListItem(outTokens[1], item))
3037 if(!strcmp(item.name, "msg"))
3039 StripQuotes(item.value, item.value);
3042 eval.active = false;
3044 if(strstr(item.value, "No symbol") && strstr(item.value, "in current context"))
3045 eval.error = symbolNotFound;
3046 else if(strstr(item.value, "Cannot access memory at address"))
3047 eval.error = memoryCantBeRead;
3049 eval.error = unknown;
3051 else if(!strcmp(item.value, "Previous frame inner to this frame (corrupt stack?)"))
3054 else if(!strncmp(item.value, "Cannot access memory at address", 31))
3057 else if(!strcmp(item.value, "Cannot find bounds of current function"))
3059 ChangeState(stopped);
3060 gdbHandle.Printf("-exec-continue\n");
3062 else if(!strcmp(item.value, "ptrace: No such process."))
3064 ChangeState(loaded);
3065 targetProcessId = 0;
3066 //ide.AdjustDebugMenus();
3068 else if(!strcmp(item.value, "Function \\\"WinMain\\\" not defined."))
3071 else if(!strcmp(item.value, "You can't do that without a process to debug."))
3073 ChangeState(loaded);
3074 targetProcessId = 0;
3075 //ide.AdjustDebugMenus();
3077 else if(strstr(item.value, "No such file or directory."))
3079 ChangeState(loaded);
3080 targetProcessId = 0;
3081 //ide.AdjustDebugMenus();
3083 else if(strstr(item.value, "During startup program exited with code "))
3085 ChangeState(loaded);
3086 targetProcessId = 0;
3087 //ide.AdjustDebugMenus();
3092 if(strlen(item.value) < MAX_F_STRING)
3095 ide.outputView.debugBox.Logf("GDB: %s\n", (s = CopyUnescapedString(item.value)));
3099 ide.outputView.debugBox.Logf("GDB: %s\n", item.value);
3105 DebuggerProtocolUnknown("Unknown error content", item.name);
3108 DebuggerProtocolUnknown("Unknown result-record", outTokens[0]);
3110 outTokens.RemoveAll();
3113 DebuggerProtocolUnknown("Unknown status-async-output", outTokens[0]);
3116 if(TokenizeList(output, ',', outTokens) && !strcmp(outTokens[0], "=thread-group-created")) //=thread-group-created,id="7611"
3118 else if(!strcmp(outTokens[0], "=thread-created")) //=thread-created,id="1",group-id="7611"
3120 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"
3123 DebuggerProtocolUnknown("Unknown notify-async-output", outTokens[0]);
3124 outTokens.RemoveAll();
3128 if(TokenizeList(output, ',', outTokens))
3130 if(!strcmp(outTokens[0],"*running"))
3132 waitingForPID = true;
3133 setWaitingForPID = true;
3135 else if(!strcmp(outTokens[0], "*stopped"))
3137 ChangeState(stopped);
3139 if(outTokens.count > 1 && TokenizeListItem(outTokens[1], item))
3141 if(!strcmp(item.name, "reason"))
3143 char * reason = item.value;
3144 StripQuotes(reason, reason);
3145 if(!strcmp(reason, "exited-normally") || !strcmp(reason, "exited") || !strcmp(reason, "exited-signalled"))
3148 if(outTokens.count > 2 && TokenizeListItem(outTokens[2], item2))
3150 StripQuotes(item2.value, item2.value);
3151 if(!strcmp(item2.name, "exit-code"))
3152 exitCode = item2.value;
3158 HandleExit(reason, exitCode);
3160 else if(!strcmp(reason, "breakpoint-hit"))
3164 printf("problem\n");
3166 stopItem = GdbDataStop { };
3168 for(i = 2; i < outTokens.count; i++)
3170 TokenizeListItem(outTokens[i], item);
3171 StripQuotes(item.value, item.value);
3172 if(!strcmp(item.name, "bkptno"))
3173 stopItem.bkptno = atoi(item.value);
3174 else if(!strcmp(item.name, "thread-id"))
3175 stopItem.threadid = atoi(item.value);
3176 else if(!strcmp(item.name, "frame"))
3178 item.value = StripCurlies(item.value);
3179 ParseFrame(stopItem.frame, item.value);
3182 DebuggerProtocolUnknown("Unknown breakpoint hit item name", item.name);
3187 else if(!strcmp(reason, "end-stepping-range"))
3191 printf("problem\n");
3193 stopItem = GdbDataStop { };
3195 for(i = 2; i < outTokens.count; i++)
3197 TokenizeListItem(outTokens[i], item);
3198 StripQuotes(item.value, item.value);
3199 if(!strcmp(item.name, "thread-id"))
3200 stopItem.threadid = atoi(item.value);
3201 else if(!strcmp(item.name, "frame"))
3203 item.value = StripCurlies(item.value);
3204 ParseFrame(stopItem.frame, item.value);
3206 else if(!strcmp(item.name, "reason"))
3208 else if(!strcmp(item.name, "bkptno"))
3211 DebuggerProtocolUnknown("Unknown end of stepping range item name", item.name);
3215 //ide.AdjustDebugMenus();
3218 else if(!strcmp(reason, "function-finished"))
3222 printf("problem\n");
3224 stopItem = GdbDataStop { };
3225 stopItem.reason = CopyString(reason);
3227 for(i = 2; i < outTokens.count; i++)
3229 TokenizeListItem(outTokens[i], item);
3230 StripQuotes(item.value, item.value);
3231 if(!strcmp(item.name, "thread-id"))
3232 stopItem.threadid = atoi(item.value);
3233 else if(!strcmp(item.name, "frame"))
3235 item.value = StripCurlies(item.value);
3236 ParseFrame(stopItem.frame, item.value);
3238 else if(!strcmp(item.name, "gdb-result-var"))
3239 stopItem.gdbResultVar = CopyString(item.value);
3240 else if(!strcmp(item.name, "return-value"))
3241 stopItem.returnValue = CopyString(item.value);
3243 DebuggerProtocolUnknown("Unknown function finished item name", item.name);
3246 event = functionEnd;
3247 //ide.AdjustDebugMenus();
3250 else if(!strcmp(reason, "signal-received"))
3254 printf("problem\n");
3256 stopItem = GdbDataStop { };
3257 stopItem.reason = CopyString(reason);
3259 for(i = 2; i < outTokens.count; i++)
3261 TokenizeListItem(outTokens[i], item);
3262 StripQuotes(item.value, item.value);
3263 if(!strcmp(item.name, "signal-name"))
3264 stopItem.name = CopyString(item.value);
3265 else if(!strcmp(item.name, "signal-meaning"))
3266 stopItem.meaning = CopyString(item.value);
3267 else if(!strcmp(item.name, "thread-id"))
3268 stopItem.threadid = atoi(item.value);
3269 else if(!strcmp(item.name, "frame"))
3271 item.value = StripCurlies(item.value);
3272 ParseFrame(stopItem.frame, item.value);
3275 DebuggerProtocolUnknown("Unknown signal reveived item name", item.name);
3277 if(!strcmp(stopItem.name, "SIGTRAP"))
3289 //ide.AdjustDebugMenus(); ide.Update(null);
3295 //ide.AdjustDebugMenus(); ide.Update(null);
3298 else if(!strcmp(reason, "watchpoint-trigger"))
3299 DebuggerProtocolUnknown("Reason watchpoint trigger not handled", "");
3300 else if(!strcmp(reason, "read-watchpoint-trigger"))
3301 DebuggerProtocolUnknown("Reason read watchpoint trigger not handled", "");
3302 else if(!strcmp(reason, "access-watchpoint-trigger"))
3303 DebuggerProtocolUnknown("Reason access watchpoint trigger not handled", "");
3304 else if(!strcmp(reason, "watchpoint-scope"))
3305 DebuggerProtocolUnknown("Reason watchpoint scope not handled", "");
3306 else if(!strcmp(reason, "location-reached"))
3307 DebuggerProtocolUnknown("Reason location reached not handled", "");
3309 DebuggerProtocolUnknown("Unknown reason", reason);
3316 DebuggerProtocolUnknown("Unknown exec-async-output", outTokens[0]);
3317 outTokens.RemoveAll();
3320 if(!strcmpi(output, "(gdb) "))
3324 char exeFile[MAX_LOCATION];
3325 int oldProcessID = targetProcessId;
3326 GetLastDirectory(targetFile, exeFile);
3330 targetProcessId = Process_GetChildExeProcessId(gdbProcessId, exeFile);
3331 if(targetProcessId || gdbHandle.Peek()) break;
3337 ChangeState(running);
3338 //ide.AdjustDebugMenus(); ide.Update(null);
3340 else if(!oldProcessID)
3342 ide.outputView.debugBox.Logf($"Debugger Error: No target process ID\n");
3343 // TO VERIFY: The rest of this block has not been thoroughly tested in this particular location
3344 gdbHandle.Printf("-gdb-exit\n");
3346 ChangeState(terminated); //loaded;
3351 for(bp : ide.workspace.breakpoints)
3352 bp.inserted = false;
3355 bp.inserted = false;
3357 bpRunToCursor.inserted = false;
3359 ide.outputView.debugBox.Logf($"Debugging stopped\n");
3360 ClearBreakDisplay();
3361 //ide.AdjustDebugMenus(); ide.Update(null);
3363 #if defined(__unix__)
3364 if(FileExists(progFifoPath)) //fileCreated)
3366 progThread.terminate = true;
3369 fifoFile.CloseInput();
3376 DeleteFile(progFifoPath);
3377 progFifoPath[0] = '\0';
3384 serialSemaphore.Release();
3387 DebuggerProtocolUnknown($"Unknown prompt", output);
3391 if(!strncmp(output, "&\"warning:", 10))
3394 content = strstr(output, "\"");
3395 StripQuotes(content, content);
3396 content = strstr(content, ":");
3402 ide.outputView.debugBox.LogRaw((s = CopyUnescapedString(content)));
3409 DebuggerProtocolUnknown($"Unknown output", output);
3411 if(!setWaitingForPID)
3412 waitingForPID = false;
3413 setWaitingForPID = false;
3421 void RunToCursorPrepare(char * absoluteFilePath, char * relativeFilePath, int lineNumber)
3425 //bpRunToCursor.Free();
3426 bpRunToCursor = Breakpoint { };
3429 bpRunToCursor = Breakpoint { };
3431 if(absoluteFilePath)
3432 bpRunToCursor.absoluteFilePath = CopyString(absoluteFilePath);
3433 if(relativeFilePath)
3434 bpRunToCursor.relativeFilePath = CopyString(relativeFilePath);
3435 bpRunToCursor.line = lineNumber;
3436 bpRunToCursor.type = runToCursor;
3437 bpRunToCursor.enabled = true;
3438 bpRunToCursor.condition = null;
3439 bpRunToCursor.ignore = 0;
3440 bpRunToCursor.level = -1;
3443 ExpressionType ::DebugEvalExpTypeError(char * result)
3449 case symbolNotFound:
3450 return symbolErrorExp;
3451 case memoryCantBeRead:
3452 return memoryErrorExp;
3454 return unknownErrorExp;
3457 char * ::EvaluateExpression(char * expression, ExpressionType * error)
3460 if(ide.projectView && ide.debugger.state == stopped)
3462 result = GdbEvaluateExpression(expression);
3463 *error = DebugEvalExpTypeError(result);
3468 *error = noDebuggerErrorExp;
3473 char * ::ReadMemory(uint address, int size, char format, ExpressionType * error)
3476 char * result = GdbReadMemoryString(address, size, format, 1, 1);
3477 if(!result || !strcmp(result, "N/A"))
3478 *error = memoryErrorExp;
3480 *error = DebugEvalExpTypeError(result);
3485 class GdbThread : Thread
3491 static char output[4096];
3492 Array<char> dynamicBuffer { minAllocSize = 4096 };
3493 DualPipe oldGdbHandle = gdbHandle;
3494 incref oldGdbHandle;
3497 while(debugger.state != terminated && gdbHandle && !gdbHandle.Eof())
3501 result = gdbHandle.Read(output, 1, sizeof(output));
3502 if(debugger.state == terminated || !gdbHandle || gdbHandle.Eof())
3510 for(c = 0; c<result; c++)
3512 if(output[c] == '\n')
3514 int pos = dynamicBuffer.size;
3515 dynamicBuffer.size += c - start;
3516 memcpy(&dynamicBuffer[pos], output + start, c - start);
3517 if(dynamicBuffer.count && dynamicBuffer[dynamicBuffer.count - 1] != '\r')
3518 // COMMENTED OUT DUE TO ISSUE #135, FIXED
3519 //if(dynamicBuffer.array[dynamicBuffer.count - 1] != '\r')
3520 dynamicBuffer.size++;
3521 dynamicBuffer[dynamicBuffer.count - 1] = '\0';
3523 // printf("%s\n", dynamicBuffer.array);
3525 debugger.GdbThreadMain(&dynamicBuffer[0]);
3526 dynamicBuffer.size = 0;
3532 int pos = dynamicBuffer.size;
3533 dynamicBuffer.size += c - start;
3534 memcpy(&dynamicBuffer[pos], output + start, c - start);
3540 printf("Got end of file from GDB!\n");
3544 delete dynamicBuffer;
3545 //if(oldGdbHandle == gdbHandle)
3546 debugger.GdbThreadExit();
3547 delete oldGdbHandle;
3553 #if defined(__unix__)
3558 #include <sys/types.h>
3563 class ProgramThread : Thread
3569 bool fileCreated = false;
3571 static char output[1000];
3574 /*if(!mkfifo(progFifoPath, mask))
3581 ide.outputView.debugBox.Logf($"err: Unable to create FIFO %s\n", progFifoPath);
3585 if(FileExists(progFifoPath)) //fileCreated)
3587 fifoFile = FileOpen(progFifoPath, read);
3591 ide.outputView.debugBox.Logf($"err: Unable to open FIFO %s for read\n", progFifoPath);
3600 fd = fileno(fifoFile.input);
3602 //fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
3606 while(!terminate && fifoFile && !fifoFile.Eof())
3609 struct timeval time;
3617 selectResult = select(fd + 1, &rs, null, null, &time);
3618 if(FD_ISSET(fd, &rs))
3620 int result = read(fd, output, sizeof(output)-1);
3621 if(!result || (result < 0 && errno != EAGAIN))
3625 output[result] = '\0';
3626 if(strcmp(output,"&\"warning: GDB: Failed to set controlling terminal: Invalid argument\\n\"\n"))
3629 ide.outputView.debugBox.Log(output);
3638 //fifoFile.CloseInput();
3641 ide.outputView.debugBox.Log("\n");
3645 if(FileExists(progFifoPath)) //fileCreated)
3647 DeleteFile(progFifoPath);
3648 progFifoPath[0] = '\0';
3656 class Argument : struct
3658 Argument prev, next;
3674 class Frame : struct
3683 property char * from { set { delete from; if(value) from = CopyUnescapedUnixPath(value); } }
3685 property char * file { set { delete file; if(value) file = CopyUnescapedUnixPath(value); } }
3686 char * absoluteFile;
3695 delete absoluteFile;
3696 args.Free(Argument::Free);
3705 class GdbDataStop : struct
3722 char * gdbResultVar;
3732 if(!strcmp(reason, "signal-received"))
3737 else if(!strcmp(reason, "function-finished"))
3739 delete gdbResultVar;
3744 if(frame) frame.Free();
3753 class GdbDataBreakpoint : struct
3762 property char * file { set { delete file; if(value) file = CopyUnescapedUnixPath(value); } }
3777 ~GdbDataBreakpoint()
3783 class Breakpoint : struct
3787 char * relativeFilePath;
3788 char * absoluteFilePath;
3796 BreakpointType type;
3799 GdbDataBreakpoint bp;
3801 char * LocationToString()
3803 char location[MAX_LOCATION+20];
3804 sprintf(location, "%s:%d", relativeFilePath, line);
3805 #if defined(__WIN32__)
3806 ChangeCh(location, '/', '\\');
3808 return CopyString(location);
3813 if(relativeFilePath && relativeFilePath[0])
3815 f.Printf(" * %d,%d,%d,%d,%s\n", enabled ? 1 : 0, ignore, level, line, relativeFilePath);
3817 f.Printf(" ~ %s\n", condition.expression);
3826 delete relativeFilePath;
3827 delete absoluteFilePath;
3837 class Watch : struct
3848 f.Printf(" ~ %s\n", expression);
3872 class DebugListItem : struct
3878 struct DebugEvaluationData
3883 uint nextBlockAddress;
3885 DebuggerEvaluationError error;
3888 class CodeLocation : struct
3891 char * absoluteFile;
3894 CodeLocation ::ParseCodeLocation(char * location)
3898 char * colon = null;
3900 char loc[MAX_LOCATION];
3901 strcpy(loc, location);
3902 for(temp = loc; temp = strstr(temp, ":"); temp++)
3910 int line = atoi(colon);
3913 CodeLocation codloc { line = line };
3914 codloc.file = CopyString(loc);
3915 codloc.absoluteFile = ide.workspace.GetAbsolutePathFromRelative(loc);
3927 delete absoluteFile;