From e8d2aee2ddabd2fac06620956c0a3a932f6f8bca Mon Sep 17 00:00:00 2001 From: Ernie Pasveer Date: Mon, 22 Sep 2025 16:55:18 -0500 Subject: [PATCH] First pass at adding print support for Objective-C objects. --- src/SeerGdbWidget.cpp | 16 +++++++- src/SeerVariableTrackerBrowserWidget.cpp | 3 ++ src/resource.qrc | 1 + src/resources/mi-python/MIObjectiveC.py | 37 +++++++++++++++++++ tests/helloobjectivec/.gitignore | 1 + tests/helloobjectivec/Makefile | 9 +++-- tests/helloobjectivec/README | 8 ++++ tests/helloobjectivec/hellodays.m | 20 ++++++++++ tests/helloobjectivec/hellodays.seer | 24 ++++++++++++ .../hellodays_breakpoints.seer | 1 + tests/helloobjectivec/hellotictactoe.m | 2 +- 11 files changed, 116 insertions(+), 6 deletions(-) create mode 100644 src/resources/mi-python/MIObjectiveC.py create mode 100644 tests/helloobjectivec/README create mode 100644 tests/helloobjectivec/hellodays.m create mode 100644 tests/helloobjectivec/hellodays.seer create mode 100644 tests/helloobjectivec/hellodays_breakpoints.seer diff --git a/src/SeerGdbWidget.cpp b/src/SeerGdbWidget.cpp index 417cade..51a28d4 100644 --- a/src/SeerGdbWidget.cpp +++ b/src/SeerGdbWidget.cpp @@ -2640,7 +2640,14 @@ void SeerGdbWidget::handleGdbDataEvaluateExpression (int expressionid, QString e return; } - handleGdbCommand(QString::number(expressionid) + "-data-evaluate-expression \"" + expression + "\""); + // Check if there's a ObjectiveC pretext. + if (expression.startsWith("oc#")) { + handleGdbCommand(QString::number(expressionid) + "-objc-evaluate-expression \"" + expression.mid(3) + "\""); + + // Otherwise handle normally. + }else{ + handleGdbCommand(QString::number(expressionid) + "-data-evaluate-expression \"" + expression + "\""); + } } void SeerGdbWidget::handleGdbVarObjCreate (int expressionid, QString expression) { @@ -2716,7 +2723,7 @@ void SeerGdbWidget::handleGdbDataListValues () { } for (int i=0; i<_dataExpressionId.size(); i++) { - handleGdbCommand(QString::number(_dataExpressionId[i]) + "-data-evaluate-expression \"" + _dataExpressionName[i] + "\""); + handleGdbDataEvaluateExpression(_dataExpressionId[i], _dataExpressionName[i]); } } @@ -2777,6 +2784,11 @@ void SeerGdbWidget::handleGdbDataAddExpression (QString expression) { void SeerGdbWidget::handleGdbDataDeleteExpressions (QString expressionids) { if (executableLaunchMode() == "") { + + // Clear expression list. + _dataExpressionId.clear(); + _dataExpressionName.clear(); + return; } diff --git a/src/SeerVariableTrackerBrowserWidget.cpp b/src/SeerVariableTrackerBrowserWidget.cpp index 80e5530..5cf087e 100644 --- a/src/SeerVariableTrackerBrowserWidget.cpp +++ b/src/SeerVariableTrackerBrowserWidget.cpp @@ -224,6 +224,9 @@ void SeerVariableTrackerBrowserWidget::handleSessionTerminated () { // Delete previous contents. variablesTreeWidget->clear(); + + // Tell the GdbWidget to forget all tracked expressions. + emit deleteVariableExpressions("*"); } void SeerVariableTrackerBrowserWidget::refresh () { diff --git a/src/resource.qrc b/src/resource.qrc index 88b0762..87b7368 100644 --- a/src/resource.qrc +++ b/src/resource.qrc @@ -86,6 +86,7 @@ resources/mi-python/MIKill.py resources/mi-python/MICheckpoint.py resources/mi-python/MICatchpoint.py + resources/mi-python/MIObjectiveC.py diff --git a/src/resources/mi-python/MIObjectiveC.py b/src/resources/mi-python/MIObjectiveC.py new file mode 100644 index 0000000..ff2be9d --- /dev/null +++ b/src/resources/mi-python/MIObjectiveC.py @@ -0,0 +1,37 @@ +# SPDX-FileCopyrightText: 2025 Ernie Pasveer +# +# SPDX-License-Identifier: MIT + +import re + +# +# Python MI command to manage gdb's Objective-C commands. +# +# https://sourceware.org/gdb/current/onlinedocs/gdb.html/Objective_002dC.html#Objective_002dC +# + +class MIObjectiveC(gdb.MICommand): + """ + Run the ObjectiveC command. + + -objc-evaluate-expression Evaluate an Objective-C object via 'print-object' and '_NSPrintForDebugger'. + + See: https://sourceware.org/gdb/current/onlinedocs/gdb.html/Objective_002dC.html#Objective_002dC + """ + + def __init__(self, name, mode): + self._mode = mode + super(MIObjectiveC, self).__init__(name) + + def invoke(self, argv): + if self._mode == "evaluate-expression": + + result = gdb.execute ("print-object " + " ".join(argv), to_string=True) + + return { "value": result.rstrip('\n')} + + else: + raise gdb.GdbError("objectivec: Invalid parameter: %s" % self._mode) + +MIObjectiveC("-objc-evaluate-expression", "evaluate-expression") + diff --git a/tests/helloobjectivec/.gitignore b/tests/helloobjectivec/.gitignore index 8761415..c0ba299 100644 --- a/tests/helloobjectivec/.gitignore +++ b/tests/helloobjectivec/.gitignore @@ -1,2 +1,3 @@ hellotictactoe +hellodays *.d diff --git a/tests/helloobjectivec/Makefile b/tests/helloobjectivec/Makefile index 4b73f13..715860d 100644 --- a/tests/helloobjectivec/Makefile +++ b/tests/helloobjectivec/Makefile @@ -1,10 +1,13 @@ .PHONY: all -all: hellotictactoe +all: hellotictactoe hellodays hellotictactoe: hellotictactoe.m - clang hellotictactoe.m -g `gnustep-config --objc-flags` -std=c99 -lobjc -lgnustep-base -o hellotictactoe + clang hellotictactoe.m `gnustep-config --objc-flags` -O0 -std=c99 -lobjc -lgnustep-base -o hellotictactoe + +hellodays: hellodays.m + clang hellodays.m `gnustep-config --objc-flags` -O0 -std=c99 -lobjc -lgnustep-base -o hellodays .PHONY: clean clean: - rm -f hellotictactoe *.d + rm -f hellotictactoe hellodays *.d diff --git a/tests/helloobjectivec/README b/tests/helloobjectivec/README new file mode 100644 index 0000000..948dc43 --- /dev/null +++ b/tests/helloobjectivec/README @@ -0,0 +1,8 @@ + +Setup the GNUStep environment. + + $ source /usr/share/GNUstep/Makefiles/GNUstep.sh + + $ export CC=/usr/bin/clang + $ export CXX=/usr/bin/clang++ + diff --git a/tests/helloobjectivec/hellodays.m b/tests/helloobjectivec/hellodays.m new file mode 100644 index 0000000..6ac2b77 --- /dev/null +++ b/tests/helloobjectivec/hellodays.m @@ -0,0 +1,20 @@ +#import + +int main(void) { + + @autoreleasepool { + + NSString* name = @"test string!!!"; + float myval = 3.75; + NSArray* weekArray; + + weekArray = [NSArray arrayWithObjects: @"Sun", @"Mon" @"Tue", @"Wed", @"Thr", @"Fri", @"Sat", nil]; + + NSLog(@"name = %@", name); + NSLog(@"myval = %f", myval); + NSLog(@"weekArray = %@", weekArray); + } + + return 0; +} + diff --git a/tests/helloobjectivec/hellodays.seer b/tests/helloobjectivec/hellodays.seer new file mode 100644 index 0000000..82cd4d6 --- /dev/null +++ b/tests/helloobjectivec/hellodays.seer @@ -0,0 +1,24 @@ +{ + "seerproject": { + "executable": "/nas/erniep/Development/seer/tests/helloobjectivec/hellodays", + "postgdbcommands": [ + "" + ], + "pregdbcommands": [ + "" + ], + "startmode": { + "arguments": "", + "breakinfunction": false, + "breakinfunctionname": "", + "breakinmain": true, + "breakpointsfile": "/nas/erniep/Development/seer/tests/helloobjectivec/hellodays_breakpoints.seer", + "nobreak": false, + "nonstopmode": false, + "randomizestartaddress": false, + "showassemblytab": false + }, + "symbolfile": "", + "workingdirectory": "" + } +} diff --git a/tests/helloobjectivec/hellodays_breakpoints.seer b/tests/helloobjectivec/hellodays_breakpoints.seer new file mode 100644 index 0000000..2806259 --- /dev/null +++ b/tests/helloobjectivec/hellodays_breakpoints.seer @@ -0,0 +1 @@ +break -source /nas/erniep/Development/seer/tests/helloobjectivec/hellodays.m -line 15 diff --git a/tests/helloobjectivec/hellotictactoe.m b/tests/helloobjectivec/hellotictactoe.m index 8145f92..4437949 100644 --- a/tests/helloobjectivec/hellotictactoe.m +++ b/tests/helloobjectivec/hellotictactoe.m @@ -130,7 +130,7 @@ - (int)getPlayerInput { int input; printf("Player %c, enter your move (1-9): ", currentPlayer); - scanf("%d", &input); + (void)scanf("%d", &input); // Clear input buffer int c;