Skip to content

Commit ee81567

Browse files
committed
Handle gdb.LazyString in DAP
Andry pointed out that the DAP code did not properly handle gdb.LazyString results from a pretty-printer, yielding: TypeError: Object of type LazyString is not JSON serializable This patch fixes the problem, partly with a small patch in varref.py, but mainly by implementing tp_str for LazyString. Reviewed-By: Eli Zaretskii <[email protected]>
1 parent 138c7d2 commit ee81567

File tree

6 files changed

+170
-2
lines changed

6 files changed

+170
-2
lines changed

gdb/NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,8 @@ show tui mouse-events
358358
gdb.Progspace that is either being added to GDB, or removed from
359359
GDB.
360360

361+
** gdb.LazyString now implements the __str__ method.
362+
361363
*** Changes in GDB 13
362364

363365
* MI version 1 is deprecated, and will be removed in GDB 14.

gdb/python/lib/gdb/dap/varref.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ def child_count(self):
173173

174174
def to_object(self):
175175
result = super().to_object()
176-
result[self.result_name] = self.printer.to_string()
176+
result[self.result_name] = str(self.printer.to_string())
177177
num_children = self.child_count()
178178
if num_children is not None:
179179
if (

gdb/python/py-lazy-string.c

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,32 @@ gdbpy_extract_lazy_string (PyObject *string, CORE_ADDR *addr,
296296
encoding->reset (lazy->encoding ? xstrdup (lazy->encoding) : NULL);
297297
}
298298

299+
/* __str__ for LazyString. */
300+
301+
static PyObject *
302+
stpy_str (PyObject *self)
303+
{
304+
lazy_string_object *str = (lazy_string_object *) self;
305+
306+
struct value_print_options opts;
307+
get_user_print_options (&opts);
308+
opts.addressprint = false;
309+
310+
string_file stream;
311+
try
312+
{
313+
struct type *type = stpy_lazy_string_elt_type (str);
314+
val_print_string (type, str->encoding, str->address, str->length,
315+
&stream, &opts);
316+
}
317+
catch (const gdb_exception &exc)
318+
{
319+
GDB_PY_HANDLE_EXCEPTION (exc);
320+
}
321+
322+
return host_string_to_python_string (stream.c_str ()).release ();
323+
}
324+
299325
GDBPY_INITIALIZE_FILE (gdbpy_initialize_lazy_string);
300326

301327

@@ -331,7 +357,7 @@ PyTypeObject lazy_string_object_type = {
331357
0, /*tp_as_mapping*/
332358
0, /*tp_hash */
333359
0, /*tp_call*/
334-
0, /*tp_str*/
360+
stpy_str, /*tp_str*/
335361
0, /*tp_getattro*/
336362
0, /*tp_setattro*/
337363
0, /*tp_as_buffer*/
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/* Copyright 2023 Free Software Foundation, Inc.
2+
3+
This file is part of GDB.
4+
5+
This program is free software; you can redistribute it and/or modify
6+
it under the terms of the GNU General Public License as published by
7+
the Free Software Foundation; either version 3 of the License, or
8+
(at your option) any later version.
9+
10+
This program is distributed in the hope that it will be useful,
11+
but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
GNU General Public License for more details.
14+
15+
You should have received a copy of the GNU General Public License
16+
along with this program. If not, see <http://www.gnu.org/licenses/>. */
17+
18+
int
19+
main ()
20+
{
21+
const char *the_string = "DEI";
22+
return 0; /* STOP */
23+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Copyright 2023 Free Software Foundation, Inc.
2+
3+
# This program is free software; you can redistribute it and/or modify
4+
# it under the terms of the GNU General Public License as published by
5+
# the Free Software Foundation; either version 3 of the License, or
6+
# (at your option) any later version.
7+
#
8+
# This program is distributed in the hope that it will be useful,
9+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
# GNU General Public License for more details.
12+
#
13+
# You should have received a copy of the GNU General Public License
14+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
15+
16+
# Test printing of gdb.LazyString objects.
17+
18+
require allow_dap_tests
19+
20+
load_lib dap-support.exp
21+
22+
standard_testfile
23+
24+
if {[build_executable ${testfile}.exp $testfile] == -1} {
25+
return
26+
}
27+
28+
set remote_python_file [gdb_remote_download host \
29+
${srcdir}/${subdir}/${testfile}.py]
30+
31+
save_vars GDBFLAGS {
32+
append GDBFLAGS " -iex \"source $remote_python_file\""
33+
34+
if {[dap_launch $testfile] == ""} {
35+
return
36+
}
37+
}
38+
39+
set line [gdb_get_line_number "STOP"]
40+
set obj [dap_check_request_and_response "set breakpoint by line number" \
41+
setBreakpoints \
42+
[format {o source [o path [%s]] breakpoints [a [o line [i %d]]]} \
43+
[list s $srcfile] $line]]
44+
set line_bpno [dap_get_breakpoint_number $obj]
45+
46+
dap_check_request_and_response "start inferior" configurationDone
47+
48+
dap_wait_for_event_and_check "stopped at line breakpoint" stopped \
49+
"body reason" breakpoint \
50+
"body hitBreakpointIds" $line_bpno
51+
52+
set bt [lindex [dap_check_request_and_response "backtrace" stackTrace \
53+
{o threadId [i 1]}] \
54+
0]
55+
set frame_id [dict get [lindex [dict get $bt body stackFrames] 0] id]
56+
57+
set scopes [dap_check_request_and_response "get scopes" scopes \
58+
[format {o frameId [i %d]} $frame_id]]
59+
set scopes [dict get [lindex $scopes 0] body scopes]
60+
61+
lassign $scopes scope reg_scope
62+
gdb_assert {[dict get $scope name] == "Locals"} "scope is locals"
63+
gdb_assert {[dict get $scope namedVariables] == 1} "one var in scope"
64+
65+
set num [dict get $scope variablesReference]
66+
set refs [lindex [dap_check_request_and_response "fetch variable" \
67+
"variables" \
68+
[format {o variablesReference [i %d] count [i 1]} \
69+
$num]] \
70+
0]
71+
72+
foreach var [dict get $refs body variables] {
73+
gdb_assert {[dict get $var name] == "the_string"} "variable name"
74+
# The result looks strange here, but only because TON does not
75+
# handle the backslash-quote sequence properly when decoding the
76+
# JSON. The actual JSON is: "value": "\"DEI\"".
77+
gdb_assert {[dict get $var value] == "\\\"DEI\\\""} "variable value"
78+
}
79+
80+
dap_shutdown
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Copyright (C) 2022-2023 Free Software Foundation, Inc.
2+
3+
# This program is free software; you can redistribute it and/or modify
4+
# it under the terms of the GNU General Public License as published by
5+
# the Free Software Foundation; either version 3 of the License, or
6+
# (at your option) any later version.
7+
#
8+
# This program is distributed in the hope that it will be useful,
9+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
# GNU General Public License for more details.
12+
#
13+
# You should have received a copy of the GNU General Public License
14+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
15+
16+
17+
import gdb
18+
19+
20+
class Printer(gdb.ValuePrinter):
21+
"""Pretty print a string"""
22+
23+
def __init__(self, val):
24+
self._val = val
25+
26+
def to_string(self):
27+
return self._val.lazy_string()
28+
29+
30+
def lookup_function(val):
31+
typ = val.type
32+
if typ.code == gdb.TYPE_CODE_PTR:
33+
return Printer(val)
34+
return None
35+
36+
37+
gdb.pretty_printers.append(lookup_function)

0 commit comments

Comments
 (0)