2010-01-14 16:03:37 +08:00
|
|
|
|
/* Python interface to lazy strings.
|
|
|
|
|
|
2017-01-01 14:50:51 +08:00
|
|
|
|
Copyright (C) 2010-2017 Free Software Foundation, Inc.
|
2010-01-14 16:03:37 +08:00
|
|
|
|
|
|
|
|
|
This file is part of GDB.
|
|
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
|
|
|
|
|
|
#include "defs.h"
|
|
|
|
|
#include "python-internal.h"
|
|
|
|
|
#include "charset.h"
|
|
|
|
|
#include "value.h"
|
|
|
|
|
#include "valprint.h"
|
|
|
|
|
#include "language.h"
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
PyObject_HEAD
|
2017-03-16 06:35:13 +08:00
|
|
|
|
|
2010-01-14 16:03:37 +08:00
|
|
|
|
/* Holds the address of the lazy string. */
|
|
|
|
|
CORE_ADDR address;
|
|
|
|
|
|
|
|
|
|
/* Holds the encoding that will be applied to the string
|
|
|
|
|
when the string is printed by GDB. If the encoding is set
|
|
|
|
|
to None then GDB will select the most appropriate
|
|
|
|
|
encoding when the sting is printed. */
|
|
|
|
|
char *encoding;
|
|
|
|
|
|
2017-03-16 06:35:13 +08:00
|
|
|
|
/* If TYPE is an array: If the length is known, then this value is the
|
|
|
|
|
array's length, otherwise it is -1.
|
|
|
|
|
If TYPE is not an array: Then this value represents the string's length.
|
|
|
|
|
In either case, if the value is -1 then the string will be fetched and
|
|
|
|
|
encoded up to the first null of appropriate width. */
|
2010-01-14 16:03:37 +08:00
|
|
|
|
long length;
|
|
|
|
|
|
2017-03-16 06:35:13 +08:00
|
|
|
|
/* This attribute holds the type of the string.
|
|
|
|
|
For example if the lazy string was created from a C "char*" then TYPE
|
|
|
|
|
represents a C "char*".
|
|
|
|
|
To get the type of the character in the string call
|
|
|
|
|
stpy_lazy_string_elt_type.
|
|
|
|
|
This is recorded as a PyObject so that we take advantage of support for
|
|
|
|
|
preserving the type should its owning objfile go away. */
|
|
|
|
|
PyObject *type;
|
2010-01-14 16:03:37 +08:00
|
|
|
|
} lazy_string_object;
|
|
|
|
|
|
Fix redefinition errors in C++ mode
In C, we can forward declare static structure instances. That doesn't
work in C++ though. C++ treats these as definitions. So then the
compiler complains about symbol redefinition, like:
src/gdb/elfread.c:1569:29: error: redefinition of ‘const sym_fns elf_sym_fns_lazy_psyms’
src/gdb/elfread.c:53:29: error: ‘const sym_fns elf_sym_fns_lazy_psyms’ previously declared here
The intent of static here is naturally to avoid making these objects
visible outside the compilation unit. The equivalent in C++ would be
to instead define the objects in the anonymous namespace. But given
that it's desirable to leave the codebase compiling as both C and C++
for a while, this just makes the objects extern.
(base_breakpoint_ops is already declared in breakpoint.h, so we can
just remove the forward declare from breakpoint.c)
gdb/ChangeLog:
2015-02-11 Tom Tromey <tromey@redhat.com>
Pedro Alves <palves@redhat.com>
* breakpoint.c (base_breakpoint_ops): Delete.
* dwarf2loc.c (dwarf_expr_ctx_funcs): Make extern.
* elfread.c (elf_sym_fns_gdb_index, elf_sym_fns_lazy_psyms): Make extern.
* guile/guile.c (guile_extension_script_ops, guile_extension_ops): Make extern.
* ppcnbsd-tdep.c (ppcnbsd2_sigtramp): Make extern.
* python/py-arch.c (arch_object_type): Make extern.
* python/py-block.c (block_syms_iterator_object_type): Make extern.
* python/py-bpevent.c (breakpoint_event_object_type): Make extern.
* python/py-cmd.c (cmdpy_object_type): Make extern.
* python/py-continueevent.c (continue_event_object_type)
* python/py-event.h (GDBPY_NEW_EVENT_TYPE): Remove 'qual'
parameter. Update all callers.
* python/py-evtregistry.c (eventregistry_object_type): Make extern.
* python/py-exitedevent.c (exited_event_object_type): Make extern.
* python/py-finishbreakpoint.c (finish_breakpoint_object_type): Make extern.
* python/py-function.c (fnpy_object_type): Make extern.
* python/py-inferior.c (inferior_object_type, membuf_object_type): Make extern.
* python/py-infevents.c (call_pre_event_object_type)
(inferior_call_post_event_object_type).
(memory_changed_event_object_type): Make extern.
* python/py-infthread.c (thread_object_type): Make extern.
* python/py-lazy-string.c (lazy_string_object_type): Make extern.
* python/py-linetable.c (linetable_entry_object_type)
(linetable_object_type, ltpy_iterator_object_type): Make extern.
* python/py-newobjfileevent.c (new_objfile_event_object_type)
(clear_objfiles_event_object_type): Make extern.
* python/py-objfile.c (objfile_object_type): Make extern.
* python/py-param.c (parmpy_object_type): Make extern.
* python/py-progspace.c (pspace_object_type): Make extern.
* python/py-signalevent.c (signal_event_object_type): Make extern.
* python/py-symtab.c (symtab_object_type, sal_object_type): Make extern.
* python/py-type.c (type_object_type, field_object_type)
(type_iterator_object_type): Make extern.
* python/python.c (python_extension_script_ops)
(python_extension_ops): Make extern.
* stap-probe.c (stap_probe_ops): Make extern.
2015-02-11 19:20:21 +08:00
|
|
|
|
extern PyTypeObject lazy_string_object_type
|
2013-05-21 04:09:01 +08:00
|
|
|
|
CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("lazy_string_object");
|
2010-01-14 16:03:37 +08:00
|
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
|
stpy_get_address (PyObject *self, void *closure)
|
|
|
|
|
{
|
|
|
|
|
lazy_string_object *self_string = (lazy_string_object *) self;
|
2010-05-18 05:23:25 +08:00
|
|
|
|
|
2011-01-27 04:53:45 +08:00
|
|
|
|
return gdb_py_long_from_ulongest (self_string->address);
|
2010-01-14 16:03:37 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
|
stpy_get_encoding (PyObject *self, void *closure)
|
|
|
|
|
{
|
|
|
|
|
lazy_string_object *self_string = (lazy_string_object *) self;
|
|
|
|
|
PyObject *result;
|
|
|
|
|
|
|
|
|
|
/* An encoding can be set to NULL by the user, so check before
|
|
|
|
|
attempting a Python FromString call. If NULL return Py_None. */
|
|
|
|
|
if (self_string->encoding)
|
|
|
|
|
result = PyString_FromString (self_string->encoding);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
result = Py_None;
|
|
|
|
|
Py_INCREF (result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static PyObject *
|
|
|
|
|
stpy_get_length (PyObject *self, void *closure)
|
|
|
|
|
{
|
|
|
|
|
lazy_string_object *self_string = (lazy_string_object *) self;
|
2010-05-18 05:23:25 +08:00
|
|
|
|
|
2010-01-14 16:03:37 +08:00
|
|
|
|
return PyLong_FromLong (self_string->length);
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-02 05:06:54 +08:00
|
|
|
|
static PyObject *
|
2010-01-14 16:03:37 +08:00
|
|
|
|
stpy_get_type (PyObject *self, void *closure)
|
|
|
|
|
{
|
|
|
|
|
lazy_string_object *str_obj = (lazy_string_object *) self;
|
2010-05-18 05:23:25 +08:00
|
|
|
|
|
2017-03-16 06:35:13 +08:00
|
|
|
|
Py_INCREF (str_obj->type);
|
|
|
|
|
return str_obj->type;
|
2010-01-14 16:03:37 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static PyObject *
|
2017-03-16 06:35:13 +08:00
|
|
|
|
stpy_convert_to_value (PyObject *self, PyObject *args)
|
2010-01-14 16:03:37 +08:00
|
|
|
|
{
|
|
|
|
|
lazy_string_object *self_string = (lazy_string_object *) self;
|
2011-10-27 17:14:27 +08:00
|
|
|
|
struct value *val = NULL;
|
2010-01-14 16:03:37 +08:00
|
|
|
|
|
2010-04-08 18:28:42 +08:00
|
|
|
|
if (self_string->address == 0)
|
|
|
|
|
{
|
2015-05-27 07:13:04 +08:00
|
|
|
|
PyErr_SetString (gdbpy_gdb_memory_error,
|
2010-04-14 21:18:55 +08:00
|
|
|
|
_("Cannot create a value from NULL."));
|
2010-04-08 18:28:42 +08:00
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 23:14:14 +08:00
|
|
|
|
TRY
|
2011-10-27 17:14:27 +08:00
|
|
|
|
{
|
2017-03-16 06:35:13 +08:00
|
|
|
|
struct type *type = type_object_to_type (self_string->type);
|
|
|
|
|
struct type *realtype;
|
|
|
|
|
|
|
|
|
|
gdb_assert (type != NULL);
|
|
|
|
|
realtype = check_typedef (type);
|
|
|
|
|
switch (TYPE_CODE (realtype))
|
|
|
|
|
{
|
|
|
|
|
case TYPE_CODE_PTR:
|
|
|
|
|
/* If a length is specified we need to convert this to an array
|
|
|
|
|
of the specified size. */
|
|
|
|
|
if (self_string->length != -1)
|
|
|
|
|
{
|
|
|
|
|
/* PR 20786: There's no way to specify an array of length zero.
|
|
|
|
|
Record a length of [0,-1] which is how Ada does it. Anything
|
|
|
|
|
we do is broken, but this is one possible solution. */
|
|
|
|
|
type = lookup_array_range_type (TYPE_TARGET_TYPE (realtype),
|
|
|
|
|
0, self_string->length - 1);
|
|
|
|
|
val = value_at_lazy (type, self_string->address);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
val = value_from_pointer (type, self_string->address);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
val = value_at_lazy (type, self_string->address);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2011-10-27 17:14:27 +08:00
|
|
|
|
}
|
Split TRY_CATCH into TRY + CATCH
This patch splits the TRY_CATCH macro into three, so that we go from
this:
~~~
volatile gdb_exception ex;
TRY_CATCH (ex, RETURN_MASK_ERROR)
{
}
if (ex.reason < 0)
{
}
~~~
to this:
~~~
TRY
{
}
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
~~~
Thus, we'll be getting rid of the local volatile exception object, and
declaring the caught exception in the catch block.
This allows reimplementing TRY/CATCH in terms of C++ exceptions when
building in C++ mode, while still allowing to build GDB in C mode
(using setjmp/longjmp), as a transition step.
TBC, after this patch, is it _not_ valid to have code between the TRY
and the CATCH blocks, like:
TRY
{
}
// some code here.
CATCH (ex, RETURN_MASK_ERROR)
{
}
END_CATCH
Just like it isn't valid to do that with C++'s native try/catch.
By switching to creating the exception object inside the CATCH block
scope, we can get rid of all the explicitly allocated volatile
exception objects all over the tree, and map the CATCH block more
directly to C++'s catch blocks.
The majority of the TRY_CATCH -> TRY+CATCH+END_CATCH conversion was
done with a script, rerun from scratch at every rebase, no manual
editing involved. After the mechanical conversion, a few places
needed manual intervention, to fix preexisting cases where we were
using the exception object outside of the TRY_CATCH block, and cases
where we were using "else" after a 'if (ex.reason) < 0)' [a CATCH
after this patch]. The result was folded into this patch so that GDB
still builds at each incremental step.
END_CATCH is necessary for two reasons:
First, because we name the exception object in the CATCH block, which
requires creating a scope, which in turn must be closed somewhere.
Declaring the exception variable in the initializer field of a for
block, like:
#define CATCH(EXCEPTION, mask) \
for (struct gdb_exception EXCEPTION; \
exceptions_state_mc_catch (&EXCEPTION, MASK); \
EXCEPTION = exception_none)
would avoid needing END_CATCH, but alas, in C mode, we build with C90,
which doesn't allow mixed declarations and code.
Second, because when TRY/CATCH are wired to real C++ try/catch, as
long as we need to handle cleanup chains, even if there's no CATCH
block that wants to catch the exception, we need for stop at every
frame in the unwind chain and run cleanups, then rethrow. That will
be done in END_CATCH.
After we require C++, we'll still need TRY/CATCH/END_CATCH until
cleanups are completely phased out -- TRY/CATCH in C++ mode will
save/restore the current cleanup chain, like in C mode, and END_CATCH
catches otherwise uncaugh exceptions, runs cleanups and rethrows, so
that C++ cleanups and exceptions can coexist.
IMO, this still makes the TRY/CATCH code look a bit more like a
newcomer would expect, so IMO worth it even if we weren't considering
C++.
gdb/ChangeLog.
2015-03-07 Pedro Alves <palves@redhat.com>
* common/common-exceptions.c (struct catcher) <exception>: No
longer a pointer to volatile exception. Now an exception value.
<mask>: Delete field.
(exceptions_state_mc_init): Remove all parameters. Adjust.
(exceptions_state_mc): No longer pop the catcher here.
(exceptions_state_mc_catch): New function.
(throw_exception): Adjust.
* common/common-exceptions.h (exceptions_state_mc_init): Remove
all parameters.
(exceptions_state_mc_catch): Declare.
(TRY_CATCH): Rename to ...
(TRY): ... this. Remove EXCEPTION and MASK parameters.
(CATCH, END_CATCH): New.
All callers adjusted.
gdb/gdbserver/ChangeLog:
2015-03-07 Pedro Alves <palves@redhat.com>
Adjust all callers of TRY_CATCH to use TRY/CATCH/END_CATCH
instead.
2015-03-07 23:14:14 +08:00
|
|
|
|
CATCH (except, RETURN_MASK_ALL)
|
|
|
|
|
{
|
|
|
|
|
GDB_PY_HANDLE_EXCEPTION (except);
|
|
|
|
|
}
|
|
|
|
|
END_CATCH
|
2011-10-27 17:14:27 +08:00
|
|
|
|
|
2010-01-14 16:03:37 +08:00
|
|
|
|
return value_to_value_object (val);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
stpy_dealloc (PyObject *self)
|
|
|
|
|
{
|
|
|
|
|
lazy_string_object *self_string = (lazy_string_object *) self;
|
2010-05-18 05:23:25 +08:00
|
|
|
|
|
2010-01-14 16:03:37 +08:00
|
|
|
|
xfree (self_string->encoding);
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-16 06:35:13 +08:00
|
|
|
|
/* Low level routine to create a <gdb.LazyString> object.
|
|
|
|
|
|
|
|
|
|
Note: If TYPE is an array, LENGTH either must be -1 (meaning to use the
|
|
|
|
|
size of the array, which may itself be unknown in which case a length of
|
|
|
|
|
-1 is still used) or must be the length of the array. */
|
|
|
|
|
|
2010-01-14 16:03:37 +08:00
|
|
|
|
PyObject *
|
|
|
|
|
gdbpy_create_lazy_string_object (CORE_ADDR address, long length,
|
2017-03-16 06:35:13 +08:00
|
|
|
|
const char *encoding, struct type *type)
|
2010-01-14 16:03:37 +08:00
|
|
|
|
{
|
|
|
|
|
lazy_string_object *str_obj = NULL;
|
2017-03-16 06:35:13 +08:00
|
|
|
|
struct type *realtype;
|
|
|
|
|
|
|
|
|
|
if (length < -1)
|
|
|
|
|
{
|
|
|
|
|
PyErr_SetString (PyExc_ValueError, _("Invalid length."));
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2010-01-14 16:03:37 +08:00
|
|
|
|
|
2010-04-08 18:28:42 +08:00
|
|
|
|
if (address == 0 && length != 0)
|
2010-01-14 16:03:37 +08:00
|
|
|
|
{
|
2015-05-27 07:13:04 +08:00
|
|
|
|
PyErr_SetString (gdbpy_gdb_memory_error,
|
2010-04-08 18:28:42 +08:00
|
|
|
|
_("Cannot create a lazy string with address 0x0, " \
|
|
|
|
|
"and a non-zero length."));
|
2010-01-14 16:03:37 +08:00
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!type)
|
|
|
|
|
{
|
|
|
|
|
PyErr_SetString (PyExc_RuntimeError,
|
2010-04-14 21:18:55 +08:00
|
|
|
|
_("A lazy string's type cannot be NULL."));
|
2010-01-14 16:03:37 +08:00
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-16 06:35:13 +08:00
|
|
|
|
realtype = check_typedef (type);
|
|
|
|
|
switch (TYPE_CODE (realtype))
|
|
|
|
|
{
|
|
|
|
|
case TYPE_CODE_ARRAY:
|
|
|
|
|
{
|
|
|
|
|
LONGEST array_length = -1;
|
|
|
|
|
LONGEST low_bound, high_bound;
|
|
|
|
|
|
|
|
|
|
if (get_array_bounds (realtype, &low_bound, &high_bound))
|
|
|
|
|
array_length = high_bound - low_bound + 1;
|
|
|
|
|
if (length == -1)
|
|
|
|
|
length = array_length;
|
|
|
|
|
else if (length != array_length)
|
|
|
|
|
{
|
|
|
|
|
PyErr_SetString (PyExc_ValueError, _("Invalid length."));
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-01-14 16:03:37 +08:00
|
|
|
|
str_obj = PyObject_New (lazy_string_object, &lazy_string_object_type);
|
|
|
|
|
if (!str_obj)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
str_obj->address = address;
|
|
|
|
|
str_obj->length = length;
|
|
|
|
|
if (encoding == NULL || !strcmp (encoding, ""))
|
|
|
|
|
str_obj->encoding = NULL;
|
|
|
|
|
else
|
|
|
|
|
str_obj->encoding = xstrdup (encoding);
|
2017-03-16 06:35:13 +08:00
|
|
|
|
str_obj->type = type_to_type_object (type);
|
2010-01-14 16:03:37 +08:00
|
|
|
|
|
|
|
|
|
return (PyObject *) str_obj;
|
|
|
|
|
}
|
|
|
|
|
|
* python/py-arch.c (gdbpy_initialize_arch): Return 'int'.
Check errors.
* python/py-auto-load.c (gdbpy_initialize_auto_load): Return 'int'.
* python/py-block.c (gdbpy_initialize_blocks): Return 'int'.
Check errors.
* python/py-breakpoint.c (gdbpy_initialize_breakpoints): Return 'int'.
Check errors.
* python/py-cmd.c (gdbpy_initialize_commands): Return 'int'.
Check errors.
* python/py-event.c (gdbpy_initialize_event): Return 'int'.
Check errors.
* python/py-event.h (GDBPY_NEW_EVENT_TYPE): Change generated
init function to return 'int'.
* python/py-evtregistry.c (gdbpy_initialize_eventregistry):
Return 'int'. Check errors.
* python/py-evts.c (gdbpy_initialize_py_events): Return 'int'.
Check errors.
* python/py-finishbreakpoint.c (gdbpy_initialize_finishbreakpoints):
Return 'int'. Check errors.
* python/py-frame.c (gdbpy_initialize_frames): Return 'int'.
Check errors.
* python/py-function.c (gdbpy_initialize_functions): Return 'int'.
Check errors.
* python/py-gdb-readline.c (gdbpy_initialize_gdb_readline):
Check errors.
* python/py-inferior.c (gdbpy_initialize_inferior): Return 'int'.
Check errors.
* python/py-infthread.c (gdbpy_initialize_thread): Return 'int'.
Check errors.
* python/py-lazy-string.c (gdbpy_initialize_lazy_string): Return 'int'.
Check errors.
* python/py-objfile.c (gdbpy_initialize_objfile): Return 'int'.
Check errors.
* python/py-param.c (gdbpy_initialize_parameters): Return 'int'.
Check errors.
* python/py-progspace.c (gdbpy_initialize_pspace): Return 'int'.
Check errors.
* python/py-symbol.c (gdbpy_initialize_symbols): Return 'int'.
Check errors.
* python/py-symtab.c (gdbpy_initialize_symtabs): Return 'int'.
Check errors.
* python/py-type.c (gdbpy_initialize_types): Return 'int'.
Check errors.
* python/py-value.c (gdbpy_initialize_values): Return 'int'.
Check errors.
* python/python-internal.h (gdbpy_initialize_auto_load,
gdbpy_initialize_values, gdbpy_initialize_frames,
gdbpy_initialize_symtabs, gdbpy_initialize_commands,
gdbpy_initialize_symbols, gdbpy_initialize_symtabs,
gdbpy_initialize_blocks, gdbpy_initialize_types,
gdbpy_initialize_functions, gdbpy_initialize_pspace,
gdbpy_initialize_objfile, gdbpy_initialize_breakpoints,
gdbpy_initialize_finishbreakpoints,
gdbpy_initialize_lazy_string, gdbpy_initialize_parameters,
gdbpy_initialize_thread, gdbpy_initialize_inferior,
gdbpy_initialize_eventregistry, gdbpy_initialize_event,
gdbpy_initialize_py_events, gdbpy_initialize_stop_event,
gdbpy_initialize_signal_event,
gdbpy_initialize_breakpoint_event,
gdbpy_initialize_continue_event,
gdbpy_initialize_exited_event, gdbpy_initialize_thread_event,
gdbpy_initialize_new_objfile_event, gdbpy_initialize_arch):
Update. Use CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION.
* python/python.c (gdb_python_initialized): New global.
(gdbpy_initialize_events): Return 'int'. Check errors.
(_initialize_python): Check errors. Set
gdb_python_initialized.
2013-05-21 04:28:52 +08:00
|
|
|
|
int
|
2010-01-14 16:03:37 +08:00
|
|
|
|
gdbpy_initialize_lazy_string (void)
|
|
|
|
|
{
|
|
|
|
|
if (PyType_Ready (&lazy_string_object_type) < 0)
|
* python/py-arch.c (gdbpy_initialize_arch): Return 'int'.
Check errors.
* python/py-auto-load.c (gdbpy_initialize_auto_load): Return 'int'.
* python/py-block.c (gdbpy_initialize_blocks): Return 'int'.
Check errors.
* python/py-breakpoint.c (gdbpy_initialize_breakpoints): Return 'int'.
Check errors.
* python/py-cmd.c (gdbpy_initialize_commands): Return 'int'.
Check errors.
* python/py-event.c (gdbpy_initialize_event): Return 'int'.
Check errors.
* python/py-event.h (GDBPY_NEW_EVENT_TYPE): Change generated
init function to return 'int'.
* python/py-evtregistry.c (gdbpy_initialize_eventregistry):
Return 'int'. Check errors.
* python/py-evts.c (gdbpy_initialize_py_events): Return 'int'.
Check errors.
* python/py-finishbreakpoint.c (gdbpy_initialize_finishbreakpoints):
Return 'int'. Check errors.
* python/py-frame.c (gdbpy_initialize_frames): Return 'int'.
Check errors.
* python/py-function.c (gdbpy_initialize_functions): Return 'int'.
Check errors.
* python/py-gdb-readline.c (gdbpy_initialize_gdb_readline):
Check errors.
* python/py-inferior.c (gdbpy_initialize_inferior): Return 'int'.
Check errors.
* python/py-infthread.c (gdbpy_initialize_thread): Return 'int'.
Check errors.
* python/py-lazy-string.c (gdbpy_initialize_lazy_string): Return 'int'.
Check errors.
* python/py-objfile.c (gdbpy_initialize_objfile): Return 'int'.
Check errors.
* python/py-param.c (gdbpy_initialize_parameters): Return 'int'.
Check errors.
* python/py-progspace.c (gdbpy_initialize_pspace): Return 'int'.
Check errors.
* python/py-symbol.c (gdbpy_initialize_symbols): Return 'int'.
Check errors.
* python/py-symtab.c (gdbpy_initialize_symtabs): Return 'int'.
Check errors.
* python/py-type.c (gdbpy_initialize_types): Return 'int'.
Check errors.
* python/py-value.c (gdbpy_initialize_values): Return 'int'.
Check errors.
* python/python-internal.h (gdbpy_initialize_auto_load,
gdbpy_initialize_values, gdbpy_initialize_frames,
gdbpy_initialize_symtabs, gdbpy_initialize_commands,
gdbpy_initialize_symbols, gdbpy_initialize_symtabs,
gdbpy_initialize_blocks, gdbpy_initialize_types,
gdbpy_initialize_functions, gdbpy_initialize_pspace,
gdbpy_initialize_objfile, gdbpy_initialize_breakpoints,
gdbpy_initialize_finishbreakpoints,
gdbpy_initialize_lazy_string, gdbpy_initialize_parameters,
gdbpy_initialize_thread, gdbpy_initialize_inferior,
gdbpy_initialize_eventregistry, gdbpy_initialize_event,
gdbpy_initialize_py_events, gdbpy_initialize_stop_event,
gdbpy_initialize_signal_event,
gdbpy_initialize_breakpoint_event,
gdbpy_initialize_continue_event,
gdbpy_initialize_exited_event, gdbpy_initialize_thread_event,
gdbpy_initialize_new_objfile_event, gdbpy_initialize_arch):
Update. Use CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION.
* python/python.c (gdb_python_initialized): New global.
(gdbpy_initialize_events): Return 'int'. Check errors.
(_initialize_python): Check errors. Set
gdb_python_initialized.
2013-05-21 04:28:52 +08:00
|
|
|
|
return -1;
|
2010-01-14 16:03:37 +08:00
|
|
|
|
|
|
|
|
|
Py_INCREF (&lazy_string_object_type);
|
* python/py-arch.c (gdbpy_initialize_arch): Return 'int'.
Check errors.
* python/py-auto-load.c (gdbpy_initialize_auto_load): Return 'int'.
* python/py-block.c (gdbpy_initialize_blocks): Return 'int'.
Check errors.
* python/py-breakpoint.c (gdbpy_initialize_breakpoints): Return 'int'.
Check errors.
* python/py-cmd.c (gdbpy_initialize_commands): Return 'int'.
Check errors.
* python/py-event.c (gdbpy_initialize_event): Return 'int'.
Check errors.
* python/py-event.h (GDBPY_NEW_EVENT_TYPE): Change generated
init function to return 'int'.
* python/py-evtregistry.c (gdbpy_initialize_eventregistry):
Return 'int'. Check errors.
* python/py-evts.c (gdbpy_initialize_py_events): Return 'int'.
Check errors.
* python/py-finishbreakpoint.c (gdbpy_initialize_finishbreakpoints):
Return 'int'. Check errors.
* python/py-frame.c (gdbpy_initialize_frames): Return 'int'.
Check errors.
* python/py-function.c (gdbpy_initialize_functions): Return 'int'.
Check errors.
* python/py-gdb-readline.c (gdbpy_initialize_gdb_readline):
Check errors.
* python/py-inferior.c (gdbpy_initialize_inferior): Return 'int'.
Check errors.
* python/py-infthread.c (gdbpy_initialize_thread): Return 'int'.
Check errors.
* python/py-lazy-string.c (gdbpy_initialize_lazy_string): Return 'int'.
Check errors.
* python/py-objfile.c (gdbpy_initialize_objfile): Return 'int'.
Check errors.
* python/py-param.c (gdbpy_initialize_parameters): Return 'int'.
Check errors.
* python/py-progspace.c (gdbpy_initialize_pspace): Return 'int'.
Check errors.
* python/py-symbol.c (gdbpy_initialize_symbols): Return 'int'.
Check errors.
* python/py-symtab.c (gdbpy_initialize_symtabs): Return 'int'.
Check errors.
* python/py-type.c (gdbpy_initialize_types): Return 'int'.
Check errors.
* python/py-value.c (gdbpy_initialize_values): Return 'int'.
Check errors.
* python/python-internal.h (gdbpy_initialize_auto_load,
gdbpy_initialize_values, gdbpy_initialize_frames,
gdbpy_initialize_symtabs, gdbpy_initialize_commands,
gdbpy_initialize_symbols, gdbpy_initialize_symtabs,
gdbpy_initialize_blocks, gdbpy_initialize_types,
gdbpy_initialize_functions, gdbpy_initialize_pspace,
gdbpy_initialize_objfile, gdbpy_initialize_breakpoints,
gdbpy_initialize_finishbreakpoints,
gdbpy_initialize_lazy_string, gdbpy_initialize_parameters,
gdbpy_initialize_thread, gdbpy_initialize_inferior,
gdbpy_initialize_eventregistry, gdbpy_initialize_event,
gdbpy_initialize_py_events, gdbpy_initialize_stop_event,
gdbpy_initialize_signal_event,
gdbpy_initialize_breakpoint_event,
gdbpy_initialize_continue_event,
gdbpy_initialize_exited_event, gdbpy_initialize_thread_event,
gdbpy_initialize_new_objfile_event, gdbpy_initialize_arch):
Update. Use CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION.
* python/python.c (gdb_python_initialized): New global.
(gdbpy_initialize_events): Return 'int'. Check errors.
(_initialize_python): Check errors. Set
gdb_python_initialized.
2013-05-21 04:28:52 +08:00
|
|
|
|
return 0;
|
2010-01-14 16:03:37 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Determine whether the printer object pointed to by OBJ is a
|
|
|
|
|
Python lazy string. */
|
|
|
|
|
int
|
|
|
|
|
gdbpy_is_lazy_string (PyObject *result)
|
|
|
|
|
{
|
|
|
|
|
return PyObject_TypeCheck (result, &lazy_string_object_type);
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-16 06:35:13 +08:00
|
|
|
|
/* Return the type of a character in lazy string LAZY. */
|
|
|
|
|
|
|
|
|
|
static struct type *
|
|
|
|
|
stpy_lazy_string_elt_type (lazy_string_object *lazy)
|
|
|
|
|
{
|
|
|
|
|
struct type *type = type_object_to_type (lazy->type);
|
|
|
|
|
struct type *realtype;
|
|
|
|
|
|
|
|
|
|
gdb_assert (type != NULL);
|
|
|
|
|
realtype = check_typedef (type);
|
|
|
|
|
|
|
|
|
|
switch (TYPE_CODE (realtype))
|
|
|
|
|
{
|
|
|
|
|
case TYPE_CODE_PTR:
|
|
|
|
|
case TYPE_CODE_ARRAY:
|
|
|
|
|
return TYPE_TARGET_TYPE (realtype);
|
|
|
|
|
default:
|
|
|
|
|
/* This is done to preserve existing behaviour. PR 20769.
|
|
|
|
|
E.g., gdb.parse_and_eval("my_int_variable").lazy_string().type. */
|
|
|
|
|
return realtype;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-10-16 02:54:13 +08:00
|
|
|
|
/* Extract the parameters from the lazy string object STRING.
|
2016-11-13 02:48:48 +08:00
|
|
|
|
ENCODING may be set to NULL, if no encoding is found. */
|
2010-01-14 16:03:37 +08:00
|
|
|
|
|
2010-10-16 02:54:13 +08:00
|
|
|
|
void
|
|
|
|
|
gdbpy_extract_lazy_string (PyObject *string, CORE_ADDR *addr,
|
2017-03-16 06:35:13 +08:00
|
|
|
|
struct type **str_elt_type,
|
2016-11-13 02:48:48 +08:00
|
|
|
|
long *length,
|
|
|
|
|
gdb::unique_xmalloc_ptr<char> *encoding)
|
2010-10-16 02:54:13 +08:00
|
|
|
|
{
|
|
|
|
|
lazy_string_object *lazy;
|
2010-01-14 16:03:37 +08:00
|
|
|
|
|
2010-10-16 02:54:13 +08:00
|
|
|
|
gdb_assert (gdbpy_is_lazy_string (string));
|
2010-01-14 16:03:37 +08:00
|
|
|
|
|
2010-10-16 02:54:13 +08:00
|
|
|
|
lazy = (lazy_string_object *) string;
|
2010-01-14 16:03:37 +08:00
|
|
|
|
|
2010-10-16 02:54:13 +08:00
|
|
|
|
*addr = lazy->address;
|
2017-03-16 06:35:13 +08:00
|
|
|
|
*str_elt_type = stpy_lazy_string_elt_type (lazy);
|
2010-10-16 02:54:13 +08:00
|
|
|
|
*length = lazy->length;
|
2016-11-13 02:48:48 +08:00
|
|
|
|
encoding->reset (lazy->encoding ? xstrdup (lazy->encoding) : NULL);
|
2010-01-14 16:03:37 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static PyMethodDef lazy_string_object_methods[] = {
|
|
|
|
|
{ "value", stpy_convert_to_value, METH_NOARGS,
|
|
|
|
|
"Create a (lazy) value that contains a pointer to the string." },
|
|
|
|
|
{NULL} /* Sentinel */
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
-Wwrite-strings: Wrap PyGetSetDef for construction with string literals
Unfortunately, PyGetSetDef's 'name' and 'doc' members are 'char *'
instead of 'const char *', meaning that in order to list-initialize
PyGetSetDef arrays using string literals requires writing explicit
'char *' casts. For example:
static PyGetSetDef value_object_getset[] = {
- { "address", valpy_get_address, NULL, "The address of the value.",
+ { (char *) "address", valpy_get_address, NULL,
+ (char *) "The address of the value.",
NULL },
- { "is_optimized_out", valpy_get_is_optimized_out, NULL,
- "Boolean telling whether the value is optimized "
+ { (char *) "is_optimized_out", valpy_get_is_optimized_out, NULL,
+ (char *) "Boolean telling whether the value is optimized "
"out (i.e., not available).",
NULL },
- { "type", valpy_get_type, NULL, "Type of the value.", NULL },
- { "dynamic_type", valpy_get_dynamic_type, NULL,
- "Dynamic type of the value.", NULL },
- { "is_lazy", valpy_get_is_lazy, NULL,
- "Boolean telling whether the value is lazy (not fetched yet\n\
+ { (char *) "type", valpy_get_type, NULL,
+ (char *) "Type of the value.", NULL },
+ { (char *) "dynamic_type", valpy_get_dynamic_type, NULL,
+ (char *) "Dynamic type of the value.", NULL },
+ { (char *) "is_lazy", valpy_get_is_lazy, NULL,
+ (char *) "Boolean telling whether the value is lazy (not fetched yet\n\
from the inferior). A lazy value is fetched when needed, or when\n\
the \"fetch_lazy()\" method is called.", NULL },
{NULL} /* Sentinel */
We have ~20 such arrays, and I first wrote a patch that fixed all of
them like that... It's not pretty...
One way to make these a bit less ugly would be add a new macro that
hides the casts, like:
#define GDBPY_GSDEF(NAME, GET, SET, DOC, CLOSURE) \
{ (char *) NAME, GET, SET, (char *) DOC, CLOSURE }
and then use it like:
static PyGetSetDef value_object_getset[] = {
GDBPY_GSDEF ("address", valpy_get_address, NULL,
"The address of the value.", NULL),
GDBPY_GSDEF ("is_optimized_out", valpy_get_is_optimized_out, NULL,
"Boolean telling whether the value is optimized ", NULL),
{NULL} /* Sentinel */
};
But since we have C++11, which gives us constexpr and list
initialization, I thought of a way that requires no changes where the
arrays are initialized:
We add a new type that extends PyGetSetDef (called gdb_PyGetSetDef),
and add constexpr constructors that accept const 'name' and 'doc', and
then list/aggregate initialization simply "calls" these matching
constructors instead.
I put "calls" in quotes, because given "constexpr", it's all done at
compile time, and there's no overhead either in binary size or at run
time. In fact, we get identical binaries, before/after this change.
Unlike the fixes that fix some old Python API to match the API of more
recent Python, this switches to using explicit "gdb_PyGetSetDef"
everywhere, just to be clear that we are using our own version of it.
gdb/ChangeLog:
2017-04-05 Pedro Alves <palves@redhat.com>
* python/python-internal.h (gdb_PyGetSetDef): New type.
* python/py-block.c (block_object_getset)
(breakpoint_object_getset): Now a gdb_PyGetSetDef array.
* python/py-event.c (event_object_getset)
(finish_breakpoint_object_getset): Likewise.
* python/py-inferior.c (inferior_object_getset): Likewise.
* python/py-infthread.c (thread_object_getset): Likewise.
* python/py-lazy-string.c (lazy_string_object_getset): Likewise.
* python/py-linetable.c (linetable_entry_object_getset): Likewise.
* python/py-objfile.c (objfile_getset): Likewise.
* python/py-progspace.c (pspace_getset): Likewise.
* python/py-record-btrace.c (btpy_insn_getset, btpy_call_getset):
Likewise.
* python/py-record.c (recpy_record_getset): Likewise.
* python/py-symbol.c (symbol_object_getset): Likewise.
* python/py-symtab.c (symtab_object_getset, sal_object_getset):
Likewise.
* python/py-type.c (type_object_getset, field_object_getset):
Likewise.
* python/py-value.c (value_object_getset): Likewise.
2017-04-06 02:21:36 +08:00
|
|
|
|
static gdb_PyGetSetDef lazy_string_object_getset[] = {
|
2010-01-14 16:03:37 +08:00
|
|
|
|
{ "address", stpy_get_address, NULL, "Address of the string.", NULL },
|
|
|
|
|
{ "encoding", stpy_get_encoding, NULL, "Encoding of the string.", NULL },
|
|
|
|
|
{ "length", stpy_get_length, NULL, "Length of the string.", NULL },
|
|
|
|
|
{ "type", stpy_get_type, NULL, "Type associated with the string.", NULL },
|
|
|
|
|
{ NULL } /* Sentinel */
|
|
|
|
|
};
|
|
|
|
|
|
Fix redefinition errors in C++ mode
In C, we can forward declare static structure instances. That doesn't
work in C++ though. C++ treats these as definitions. So then the
compiler complains about symbol redefinition, like:
src/gdb/elfread.c:1569:29: error: redefinition of ‘const sym_fns elf_sym_fns_lazy_psyms’
src/gdb/elfread.c:53:29: error: ‘const sym_fns elf_sym_fns_lazy_psyms’ previously declared here
The intent of static here is naturally to avoid making these objects
visible outside the compilation unit. The equivalent in C++ would be
to instead define the objects in the anonymous namespace. But given
that it's desirable to leave the codebase compiling as both C and C++
for a while, this just makes the objects extern.
(base_breakpoint_ops is already declared in breakpoint.h, so we can
just remove the forward declare from breakpoint.c)
gdb/ChangeLog:
2015-02-11 Tom Tromey <tromey@redhat.com>
Pedro Alves <palves@redhat.com>
* breakpoint.c (base_breakpoint_ops): Delete.
* dwarf2loc.c (dwarf_expr_ctx_funcs): Make extern.
* elfread.c (elf_sym_fns_gdb_index, elf_sym_fns_lazy_psyms): Make extern.
* guile/guile.c (guile_extension_script_ops, guile_extension_ops): Make extern.
* ppcnbsd-tdep.c (ppcnbsd2_sigtramp): Make extern.
* python/py-arch.c (arch_object_type): Make extern.
* python/py-block.c (block_syms_iterator_object_type): Make extern.
* python/py-bpevent.c (breakpoint_event_object_type): Make extern.
* python/py-cmd.c (cmdpy_object_type): Make extern.
* python/py-continueevent.c (continue_event_object_type)
* python/py-event.h (GDBPY_NEW_EVENT_TYPE): Remove 'qual'
parameter. Update all callers.
* python/py-evtregistry.c (eventregistry_object_type): Make extern.
* python/py-exitedevent.c (exited_event_object_type): Make extern.
* python/py-finishbreakpoint.c (finish_breakpoint_object_type): Make extern.
* python/py-function.c (fnpy_object_type): Make extern.
* python/py-inferior.c (inferior_object_type, membuf_object_type): Make extern.
* python/py-infevents.c (call_pre_event_object_type)
(inferior_call_post_event_object_type).
(memory_changed_event_object_type): Make extern.
* python/py-infthread.c (thread_object_type): Make extern.
* python/py-lazy-string.c (lazy_string_object_type): Make extern.
* python/py-linetable.c (linetable_entry_object_type)
(linetable_object_type, ltpy_iterator_object_type): Make extern.
* python/py-newobjfileevent.c (new_objfile_event_object_type)
(clear_objfiles_event_object_type): Make extern.
* python/py-objfile.c (objfile_object_type): Make extern.
* python/py-param.c (parmpy_object_type): Make extern.
* python/py-progspace.c (pspace_object_type): Make extern.
* python/py-signalevent.c (signal_event_object_type): Make extern.
* python/py-symtab.c (symtab_object_type, sal_object_type): Make extern.
* python/py-type.c (type_object_type, field_object_type)
(type_iterator_object_type): Make extern.
* python/python.c (python_extension_script_ops)
(python_extension_ops): Make extern.
* stap-probe.c (stap_probe_ops): Make extern.
2015-02-11 19:20:21 +08:00
|
|
|
|
PyTypeObject lazy_string_object_type = {
|
2012-12-13 00:47:30 +08:00
|
|
|
|
PyVarObject_HEAD_INIT (NULL, 0)
|
2010-01-14 16:03:37 +08:00
|
|
|
|
"gdb.LazyString", /*tp_name*/
|
|
|
|
|
sizeof (lazy_string_object), /*tp_basicsize*/
|
|
|
|
|
0, /*tp_itemsize*/
|
|
|
|
|
stpy_dealloc, /*tp_dealloc*/
|
|
|
|
|
0, /*tp_print*/
|
|
|
|
|
0, /*tp_getattr*/
|
|
|
|
|
0, /*tp_setattr*/
|
|
|
|
|
0, /*tp_compare*/
|
|
|
|
|
0, /*tp_repr*/
|
|
|
|
|
0, /*tp_as_number*/
|
|
|
|
|
0, /*tp_as_sequence*/
|
|
|
|
|
0, /*tp_as_mapping*/
|
|
|
|
|
0, /*tp_hash */
|
|
|
|
|
0, /*tp_call*/
|
|
|
|
|
0, /*tp_str*/
|
|
|
|
|
0, /*tp_getattro*/
|
|
|
|
|
0, /*tp_setattro*/
|
|
|
|
|
0, /*tp_as_buffer*/
|
|
|
|
|
Py_TPFLAGS_DEFAULT, /*tp_flags*/
|
|
|
|
|
"GDB lazy string object", /* tp_doc */
|
|
|
|
|
0, /* tp_traverse */
|
|
|
|
|
0, /* tp_clear */
|
|
|
|
|
0, /* tp_richcompare */
|
|
|
|
|
0, /* tp_weaklistoffset */
|
|
|
|
|
0, /* tp_iter */
|
|
|
|
|
0, /* tp_iternext */
|
|
|
|
|
lazy_string_object_methods, /* tp_methods */
|
|
|
|
|
0, /* tp_members */
|
|
|
|
|
lazy_string_object_getset /* tp_getset */
|
|
|
|
|
};
|