1/* Python interface to inferiors.
2
3   Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
4
5   This file is part of GDB.
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 3 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19
20#include "defs.h"
21#include "exceptions.h"
22#include "gdbcore.h"
23#include "gdbthread.h"
24#include "inferior.h"
25#include "observer.h"
26#include "python-internal.h"
27#include "arch-utils.h"
28#include "language.h"
29#include "gdb_signals.h"
30#include "py-event.h"
31#include "py-stopevent.h"
32
33struct threadlist_entry {
34  thread_object *thread_obj;
35  struct threadlist_entry *next;
36};
37
38typedef struct
39{
40  PyObject_HEAD
41
42  /* The inferior we represent.  */
43  struct inferior *inferior;
44
45  /* thread_object instances under this inferior.  This list owns a
46     reference to each object it contains.  */
47  struct threadlist_entry *threads;
48
49  /* Number of threads in the list.  */
50  int nthreads;
51} inferior_object;
52
53static PyTypeObject inferior_object_type;
54
55static const struct inferior_data *infpy_inf_data_key;
56
57typedef struct {
58  PyObject_HEAD
59  void *buffer;
60
61  /* These are kept just for mbpy_str.  */
62  CORE_ADDR addr;
63  CORE_ADDR length;
64} membuf_object;
65
66static PyTypeObject membuf_object_type;
67
68/* Require that INFERIOR be a valid inferior ID.  */
69#define INFPY_REQUIRE_VALID(Inferior)				\
70  do {								\
71    if (!Inferior->inferior)					\
72      {								\
73	PyErr_SetString (PyExc_RuntimeError,			\
74			 _("Inferior no longer exists."));	\
75	return NULL;						\
76      }								\
77  } while (0)
78
79static void
80python_on_normal_stop (struct bpstats *bs, int print_frame)
81{
82  struct cleanup *cleanup;
83  enum target_signal stop_signal;
84
85  if (!find_thread_ptid (inferior_ptid))
86      return;
87
88  stop_signal = inferior_thread ()->suspend.stop_signal;
89
90  cleanup = ensure_python_env (get_current_arch (), current_language);
91
92  if (emit_stop_event (bs, stop_signal) < 0)
93    gdbpy_print_stack ();
94
95  do_cleanups (cleanup);
96}
97
98static void
99python_on_resume (ptid_t ptid)
100{
101  struct cleanup *cleanup;
102
103  cleanup = ensure_python_env (target_gdbarch, current_language);
104
105  if (emit_continue_event (ptid) < 0)
106    gdbpy_print_stack ();
107
108  do_cleanups (cleanup);
109}
110
111static void
112python_inferior_exit (struct inferior *inf)
113{
114  struct cleanup *cleanup;
115  const LONGEST *exit_code = NULL;
116
117  cleanup = ensure_python_env (target_gdbarch, current_language);
118
119  if (inf->has_exit_code)
120    exit_code = &inf->exit_code;
121
122  if (emit_exited_event (exit_code) < 0)
123    gdbpy_print_stack ();
124
125  do_cleanups (cleanup);
126}
127
128/* Return a borrowed reference to the Python object of type Inferior
129   representing INFERIOR.  If the object has already been created,
130   return it,  otherwise, create it.  Return NULL on failure.  */
131PyObject *
132inferior_to_inferior_object (struct inferior *inferior)
133{
134  inferior_object *inf_obj;
135
136  inf_obj = inferior_data (inferior, infpy_inf_data_key);
137  if (!inf_obj)
138    {
139      struct cleanup *cleanup;
140      cleanup = ensure_python_env (python_gdbarch, python_language);
141
142      inf_obj = PyObject_New (inferior_object, &inferior_object_type);
143      if (!inf_obj)
144	{
145	  do_cleanups (cleanup);
146	  return NULL;
147	}
148
149      inf_obj->inferior = inferior;
150      inf_obj->threads = NULL;
151      inf_obj->nthreads = 0;
152
153      set_inferior_data (inferior, infpy_inf_data_key, inf_obj);
154
155      do_cleanups (cleanup);
156    }
157
158  return (PyObject *) inf_obj;
159}
160
161/* Finds the Python Inferior object for the given PID.  Returns a
162   borrowed reference, or NULL if PID does not match any inferior
163   object.  */
164
165PyObject *
166find_inferior_object (int pid)
167{
168  struct inflist_entry *p;
169  struct inferior *inf = find_inferior_pid (pid);
170
171  if (inf)
172    return inferior_to_inferior_object (inf);
173
174  return NULL;
175}
176
177thread_object *
178find_thread_object (ptid_t ptid)
179{
180  int pid;
181  struct threadlist_entry *thread;
182  PyObject *inf_obj;
183
184  pid = PIDGET (ptid);
185  if (pid == 0)
186    return NULL;
187
188  inf_obj = find_inferior_object (pid);
189
190  if (inf_obj)
191    for (thread = ((inferior_object *)inf_obj)->threads; thread;
192	 thread = thread->next)
193      if (ptid_equal (thread->thread_obj->thread->ptid, ptid))
194	return thread->thread_obj;
195
196  return NULL;
197}
198
199static void
200add_thread_object (struct thread_info *tp)
201{
202  struct cleanup *cleanup;
203  thread_object *thread_obj;
204  inferior_object *inf_obj;
205  struct threadlist_entry *entry;
206
207  cleanup = ensure_python_env (python_gdbarch, python_language);
208
209  thread_obj = create_thread_object (tp);
210  if (!thread_obj)
211    {
212      gdbpy_print_stack ();
213      do_cleanups (cleanup);
214      return;
215    }
216
217  inf_obj = (inferior_object *) thread_obj->inf_obj;
218
219  entry = xmalloc (sizeof (struct threadlist_entry));
220  entry->thread_obj = thread_obj;
221  entry->next = inf_obj->threads;
222
223  inf_obj->threads = entry;
224  inf_obj->nthreads++;
225
226  do_cleanups (cleanup);
227}
228
229static void
230delete_thread_object (struct thread_info *tp, int ignore)
231{
232  struct cleanup *cleanup;
233  inferior_object *inf_obj;
234  thread_object *thread_obj;
235  struct threadlist_entry **entry, *tmp;
236
237  inf_obj = (inferior_object *) find_inferior_object (PIDGET(tp->ptid));
238  if (!inf_obj)
239    return;
240
241  /* Find thread entry in its inferior's thread_list.  */
242  for (entry = &inf_obj->threads; *entry != NULL; entry =
243	 &(*entry)->next)
244    if ((*entry)->thread_obj->thread == tp)
245      break;
246
247  if (!*entry)
248    return;
249
250  cleanup = ensure_python_env (python_gdbarch, python_language);
251
252  tmp = *entry;
253  tmp->thread_obj->thread = NULL;
254
255  *entry = (*entry)->next;
256  inf_obj->nthreads--;
257
258  Py_DECREF (tmp->thread_obj);
259  xfree (tmp);
260
261  do_cleanups (cleanup);
262}
263
264static PyObject *
265infpy_threads (PyObject *self, PyObject *args)
266{
267  int i;
268  struct threadlist_entry *entry;
269  inferior_object *inf_obj = (inferior_object *) self;
270  PyObject *tuple;
271
272  INFPY_REQUIRE_VALID (inf_obj);
273
274  tuple = PyTuple_New (inf_obj->nthreads);
275  if (!tuple)
276    return NULL;
277
278  for (i = 0, entry = inf_obj->threads; i < inf_obj->nthreads;
279       i++, entry = entry->next)
280    {
281      Py_INCREF (entry->thread_obj);
282      PyTuple_SET_ITEM (tuple, i, (PyObject *) entry->thread_obj);
283    }
284
285  return tuple;
286}
287
288static PyObject *
289infpy_get_num (PyObject *self, void *closure)
290{
291  inferior_object *inf = (inferior_object *) self;
292
293  INFPY_REQUIRE_VALID (inf);
294
295  return PyLong_FromLong (inf->inferior->num);
296}
297
298static PyObject *
299infpy_get_pid (PyObject *self, void *closure)
300{
301  inferior_object *inf = (inferior_object *) self;
302
303  INFPY_REQUIRE_VALID (inf);
304
305  return PyLong_FromLong (inf->inferior->pid);
306}
307
308static PyObject *
309infpy_get_was_attached (PyObject *self, void *closure)
310{
311  inferior_object *inf = (inferior_object *) self;
312
313  INFPY_REQUIRE_VALID (inf);
314  if (inf->inferior->attach_flag)
315    Py_RETURN_TRUE;
316  Py_RETURN_FALSE;
317}
318
319static int
320build_inferior_list (struct inferior *inf, void *arg)
321{
322  PyObject *list = arg;
323  PyObject *inferior = inferior_to_inferior_object (inf);
324
325  if (PyList_Append (list, inferior))
326    return 1;
327
328  return 0;
329}
330
331/* Implementation of gdb.inferiors () -> (gdb.Inferior, ...).
332   Returns a tuple of all inferiors.  */
333PyObject *
334gdbpy_inferiors (PyObject *unused, PyObject *unused2)
335{
336  int i = 0;
337  PyObject *list, *inferior;
338  struct inferior *inf;
339
340  list = PyList_New (0);
341  if (!list)
342    return NULL;
343
344  if (iterate_over_inferiors (build_inferior_list, list))
345    {
346      Py_DECREF (list);
347      return NULL;
348    }
349
350  return PyList_AsTuple (list);
351}
352
353/* Membuf and memory manipulation.  */
354
355/* Implementation of gdb.read_memory (address, length).
356   Returns a Python buffer object with LENGTH bytes of the inferior's
357   memory at ADDRESS.  Both arguments are integers.  Returns NULL on error,
358   with a python exception set.  */
359static PyObject *
360infpy_read_memory (PyObject *self, PyObject *args, PyObject *kw)
361{
362  int error = 0;
363  CORE_ADDR addr, length;
364  void *buffer = NULL;
365  membuf_object *membuf_obj;
366  PyObject *addr_obj, *length_obj;
367  struct cleanup *cleanups;
368  volatile struct gdb_exception except;
369  static char *keywords[] = { "address", "length", NULL };
370
371  if (! PyArg_ParseTupleAndKeywords (args, kw, "OO", keywords,
372				     &addr_obj, &length_obj))
373    return NULL;
374
375  cleanups = make_cleanup (null_cleanup, NULL);
376
377  TRY_CATCH (except, RETURN_MASK_ALL)
378    {
379      if (!get_addr_from_python (addr_obj, &addr)
380	  || !get_addr_from_python (length_obj, &length))
381	{
382	  error = 1;
383	  break;
384	}
385
386      buffer = xmalloc (length);
387      make_cleanup (xfree, buffer);
388
389      read_memory (addr, buffer, length);
390    }
391  if (except.reason < 0)
392    {
393      do_cleanups (cleanups);
394      GDB_PY_HANDLE_EXCEPTION (except);
395    }
396
397  if (error)
398    {
399      do_cleanups (cleanups);
400      return NULL;
401    }
402
403  membuf_obj = PyObject_New (membuf_object, &membuf_object_type);
404  if (membuf_obj == NULL)
405    {
406      PyErr_SetString (PyExc_MemoryError,
407		       _("Could not allocate memory buffer object."));
408      do_cleanups (cleanups);
409      return NULL;
410    }
411
412  discard_cleanups (cleanups);
413
414  membuf_obj->buffer = buffer;
415  membuf_obj->addr = addr;
416  membuf_obj->length = length;
417
418  return PyBuffer_FromReadWriteObject ((PyObject *) membuf_obj, 0,
419				       Py_END_OF_BUFFER);
420}
421
422/* Implementation of gdb.write_memory (address, buffer [, length]).
423   Writes the contents of BUFFER (a Python object supporting the read
424   buffer protocol) at ADDRESS in the inferior's memory.  Write LENGTH
425   bytes from BUFFER, or its entire contents if the argument is not
426   provided.  The function returns nothing.  Returns NULL on error, with
427   a python exception set.  */
428static PyObject *
429infpy_write_memory (PyObject *self, PyObject *args, PyObject *kw)
430{
431  int buf_len, error = 0;
432  const char *buffer;
433  CORE_ADDR addr, length;
434  PyObject *addr_obj, *length_obj = NULL;
435  volatile struct gdb_exception except;
436  static char *keywords[] = { "address", "buffer", "length", NULL };
437
438
439  if (! PyArg_ParseTupleAndKeywords (args, kw, "Os#|O", keywords,
440				     &addr_obj, &buffer, &buf_len,
441				     &length_obj))
442    return NULL;
443
444  TRY_CATCH (except, RETURN_MASK_ALL)
445    {
446      if (!get_addr_from_python (addr_obj, &addr))
447	{
448	  error = 1;
449	  break;
450	}
451
452      if (!length_obj)
453	length = buf_len;
454      else if (!get_addr_from_python (length_obj, &length))
455	{
456	  error = 1;
457	  break;
458	}
459      write_memory (addr, buffer, length);
460    }
461  GDB_PY_HANDLE_EXCEPTION (except);
462
463  if (error)
464    return NULL;
465
466  Py_RETURN_NONE;
467}
468
469/* Destructor of Membuf objects.  */
470static void
471mbpy_dealloc (PyObject *self)
472{
473  xfree (((membuf_object *) self)->buffer);
474  self->ob_type->tp_free (self);
475}
476
477/* Return a description of the Membuf object.  */
478static PyObject *
479mbpy_str (PyObject *self)
480{
481  membuf_object *membuf_obj = (membuf_object *) self;
482
483  return PyString_FromFormat (_("Memory buffer for address %s, \
484which is %s bytes long."),
485			      paddress (python_gdbarch, membuf_obj->addr),
486			      pulongest (membuf_obj->length));
487}
488
489static Py_ssize_t
490get_read_buffer (PyObject *self, Py_ssize_t segment, void **ptrptr)
491{
492  membuf_object *membuf_obj = (membuf_object *) self;
493
494  if (segment)
495    {
496      PyErr_SetString (PyExc_SystemError,
497		       _("The memory buffer supports only one segment."));
498      return -1;
499    }
500
501  *ptrptr = membuf_obj->buffer;
502
503  return membuf_obj->length;
504}
505
506static Py_ssize_t
507get_write_buffer (PyObject *self, Py_ssize_t segment, void **ptrptr)
508{
509  return get_read_buffer (self, segment, ptrptr);
510}
511
512static Py_ssize_t
513get_seg_count (PyObject *self, Py_ssize_t *lenp)
514{
515  if (lenp)
516    *lenp = ((membuf_object *) self)->length;
517
518  return 1;
519}
520
521static Py_ssize_t
522get_char_buffer (PyObject *self, Py_ssize_t segment, char **ptrptr)
523{
524  void *ptr = NULL;
525  Py_ssize_t ret;
526
527  ret = get_read_buffer (self, segment, &ptr);
528  *ptrptr = (char *) ptr;
529
530  return ret;
531}
532
533/* Implementation of
534   gdb.search_memory (address, length, pattern).  ADDRESS is the
535   address to start the search.  LENGTH specifies the scope of the
536   search from ADDRESS.  PATTERN is the pattern to search for (and
537   must be a Python object supporting the buffer protocol).
538   Returns a Python Long object holding the address where the pattern
539   was located, or if the pattern was not found, returns None.  Returns NULL
540   on error, with a python exception set.  */
541static PyObject *
542infpy_search_memory (PyObject *self, PyObject *args, PyObject *kw)
543{
544  CORE_ADDR start_addr, length;
545  static char *keywords[] = { "address", "length", "pattern", NULL };
546  PyObject *pattern, *start_addr_obj, *length_obj;
547  volatile struct gdb_exception except;
548  Py_ssize_t pattern_size;
549  const void *buffer;
550  CORE_ADDR found_addr;
551  int found = 0;
552
553  if (! PyArg_ParseTupleAndKeywords (args, kw, "OOO", keywords,
554				     &start_addr_obj, &length_obj,
555				     &pattern))
556    return NULL;
557
558  if (get_addr_from_python (start_addr_obj, &start_addr)
559      && get_addr_from_python (length_obj, &length))
560    {
561      if (!length)
562	{
563	  PyErr_SetString (PyExc_ValueError,
564			   _("Search range is empty."));
565	  return NULL;
566	}
567      /* Watch for overflows.  */
568      else if (length > CORE_ADDR_MAX
569	       || (start_addr + length - 1) < start_addr)
570	{
571	  PyErr_SetString (PyExc_ValueError,
572			   _("The search range is too large."));
573
574	  return NULL;
575	}
576    }
577  else
578    return NULL;
579
580  if (!PyObject_CheckReadBuffer (pattern))
581    {
582      PyErr_SetString (PyExc_RuntimeError,
583		       _("The pattern is not a Python buffer."));
584
585      return NULL;
586    }
587
588  if (PyObject_AsReadBuffer (pattern, &buffer, &pattern_size) == -1)
589    return NULL;
590
591  TRY_CATCH (except, RETURN_MASK_ALL)
592    {
593      found = target_search_memory (start_addr, length,
594				    buffer, pattern_size,
595				    &found_addr);
596    }
597  GDB_PY_HANDLE_EXCEPTION (except);
598
599  if (found)
600    return PyLong_FromLong (found_addr);
601  else
602    Py_RETURN_NONE;
603}
604
605/* Implementation of gdb.Inferior.is_valid (self) -> Boolean.
606   Returns True if this inferior object still exists in GDB.  */
607
608static PyObject *
609infpy_is_valid (PyObject *self, PyObject *args)
610{
611  inferior_object *inf = (inferior_object *) self;
612
613  if (! inf->inferior)
614    Py_RETURN_FALSE;
615
616  Py_RETURN_TRUE;
617}
618
619
620/* Clear the INFERIOR pointer in an Inferior object and clear the
621   thread list.  */
622static void
623py_free_inferior (struct inferior *inf, void *datum)
624{
625
626  struct cleanup *cleanup;
627  inferior_object *inf_obj = datum;
628  struct threadlist_entry *th_entry, *th_tmp;
629
630  cleanup = ensure_python_env (python_gdbarch, python_language);
631
632  inf_obj->inferior = NULL;
633
634  /* Deallocate threads list.  */
635  for (th_entry = inf_obj->threads; th_entry != NULL;)
636    {
637      Py_DECREF (th_entry->thread_obj);
638
639      th_tmp = th_entry;
640      th_entry = th_entry->next;
641      xfree (th_tmp);
642    }
643
644  inf_obj->nthreads = 0;
645
646  Py_DECREF ((PyObject *) inf_obj);
647  do_cleanups (cleanup);
648}
649
650void
651gdbpy_initialize_inferior (void)
652{
653  if (PyType_Ready (&inferior_object_type) < 0)
654    return;
655
656  Py_INCREF (&inferior_object_type);
657  PyModule_AddObject (gdb_module, "Inferior",
658		      (PyObject *) &inferior_object_type);
659
660  infpy_inf_data_key =
661    register_inferior_data_with_cleanup (py_free_inferior);
662
663  observer_attach_new_thread (add_thread_object);
664  observer_attach_thread_exit (delete_thread_object);
665  observer_attach_normal_stop (python_on_normal_stop);
666  observer_attach_target_resumed (python_on_resume);
667  observer_attach_inferior_exit (python_inferior_exit);
668
669  if (PyType_Ready (&membuf_object_type) < 0)
670    return;
671
672  Py_INCREF (&membuf_object_type);
673  PyModule_AddObject (gdb_module, "Membuf", (PyObject *)
674		      &membuf_object_type);
675}
676
677static PyGetSetDef inferior_object_getset[] =
678{
679  { "num", infpy_get_num, NULL, "ID of inferior, as assigned by GDB.", NULL },
680  { "pid", infpy_get_pid, NULL, "PID of inferior, as assigned by the OS.",
681    NULL },
682  { "was_attached", infpy_get_was_attached, NULL,
683    "True if the inferior was created using 'attach'.", NULL },
684  { NULL }
685};
686
687static PyMethodDef inferior_object_methods[] =
688{
689  { "is_valid", infpy_is_valid, METH_NOARGS,
690    "is_valid () -> Boolean.\n\
691Return true if this inferior is valid, false if not." },
692  { "threads", infpy_threads, METH_NOARGS,
693    "Return all the threads of this inferior." },
694  { "read_memory", (PyCFunction) infpy_read_memory,
695    METH_VARARGS | METH_KEYWORDS,
696    "read_memory (address, length) -> buffer\n\
697Return a buffer object for reading from the inferior's memory." },
698  { "write_memory", (PyCFunction) infpy_write_memory,
699    METH_VARARGS | METH_KEYWORDS,
700    "write_memory (address, buffer [, length])\n\
701Write the given buffer object to the inferior's memory." },
702  { "search_memory", (PyCFunction) infpy_search_memory,
703    METH_VARARGS | METH_KEYWORDS,
704    "search_memory (address, length, pattern) -> long\n\
705Return a long with the address of a match, or None." },
706  { NULL }
707};
708
709static PyTypeObject inferior_object_type =
710{
711  PyObject_HEAD_INIT (NULL)
712  0,				  /* ob_size */
713  "gdb.Inferior",		  /* tp_name */
714  sizeof (inferior_object),	  /* tp_basicsize */
715  0,				  /* tp_itemsize */
716  0,				  /* tp_dealloc */
717  0,				  /* tp_print */
718  0,				  /* tp_getattr */
719  0,				  /* tp_setattr */
720  0,				  /* tp_compare */
721  0,				  /* tp_repr */
722  0,				  /* tp_as_number */
723  0,				  /* tp_as_sequence */
724  0,				  /* tp_as_mapping */
725  0,				  /* tp_hash  */
726  0,				  /* tp_call */
727  0,				  /* tp_str */
728  0,				  /* tp_getattro */
729  0,				  /* tp_setattro */
730  0,				  /* tp_as_buffer */
731  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER,  /* tp_flags */
732  "GDB inferior object",	  /* tp_doc */
733  0,				  /* tp_traverse */
734  0,				  /* tp_clear */
735  0,				  /* tp_richcompare */
736  0,				  /* tp_weaklistoffset */
737  0,				  /* tp_iter */
738  0,				  /* tp_iternext */
739  inferior_object_methods,	  /* tp_methods */
740  0,				  /* tp_members */
741  inferior_object_getset,	  /* tp_getset */
742  0,				  /* tp_base */
743  0,				  /* tp_dict */
744  0,				  /* tp_descr_get */
745  0,				  /* tp_descr_set */
746  0,				  /* tp_dictoffset */
747  0,				  /* tp_init */
748  0				  /* tp_alloc */
749};
750
751/* Python doesn't provide a decent way to get compatibility here.  */
752#if HAVE_LIBPYTHON2_4
753#define CHARBUFFERPROC_NAME getcharbufferproc
754#else
755#define CHARBUFFERPROC_NAME charbufferproc
756#endif
757
758static PyBufferProcs buffer_procs = {
759  get_read_buffer,
760  get_write_buffer,
761  get_seg_count,
762  /* The cast here works around a difference between Python 2.4 and
763     Python 2.5.  */
764  (CHARBUFFERPROC_NAME) get_char_buffer
765};
766
767static PyTypeObject membuf_object_type = {
768  PyObject_HEAD_INIT (NULL)
769  0,				  /*ob_size*/
770  "gdb.Membuf",			  /*tp_name*/
771  sizeof (membuf_object),	  /*tp_basicsize*/
772  0,				  /*tp_itemsize*/
773  mbpy_dealloc,			  /*tp_dealloc*/
774  0,				  /*tp_print*/
775  0,				  /*tp_getattr*/
776  0,				  /*tp_setattr*/
777  0,				  /*tp_compare*/
778  0,				  /*tp_repr*/
779  0,				  /*tp_as_number*/
780  0,				  /*tp_as_sequence*/
781  0,				  /*tp_as_mapping*/
782  0,				  /*tp_hash */
783  0,				  /*tp_call*/
784  mbpy_str,			  /*tp_str*/
785  0,				  /*tp_getattro*/
786  0,				  /*tp_setattro*/
787  &buffer_procs,		  /*tp_as_buffer*/
788  Py_TPFLAGS_DEFAULT,		  /*tp_flags*/
789  "GDB memory buffer object", 	  /*tp_doc*/
790  0,				  /* tp_traverse */
791  0,				  /* tp_clear */
792  0,				  /* tp_richcompare */
793  0,				  /* tp_weaklistoffset */
794  0,				  /* tp_iter */
795  0,				  /* tp_iternext */
796  0,				  /* tp_methods */
797  0,				  /* tp_members */
798  0,				  /* tp_getset */
799  0,				  /* tp_base */
800  0,				  /* tp_dict */
801  0,				  /* tp_descr_get */
802  0,				  /* tp_descr_set */
803  0,				  /* tp_dictoffset */
804  0,				  /* tp_init */
805  0,				  /* tp_alloc */
806  PyType_GenericNew		  /* tp_new */
807};
808