gdb.rb 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README ADDED
@@ -0,0 +1,229 @@
1
+ gdb7 hooks for MRI
2
+ (c) 2009 Aman Gupta (tmm1)
3
+
4
+ === Usage
5
+
6
+ $ ps aux | grep deploy.rb
7
+ 13074 0.0 0.7 90164 31720 ? R Sep23 2:21 /usr/bin/ruby /usr/bin/god -c deploy.rb
8
+
9
+ $ sudo gdb.rb 13074
10
+ GNU gdb (GDB) 7.0
11
+ Reading symbols from /usr/bin/ruby...done.
12
+ Attaching to program: /usr/bin/ruby, process 13074
13
+ 0x00007fa8b9cb3c93 in select () from /lib/libc.so.6
14
+
15
+ (gdb) ruby threads list
16
+ 0x1589000 main thread THREAD_STOPPED WAIT_JOIN(0x19ef400) 4417 bytes
17
+ 0x19ef400 thread THREAD_STOPPED WAIT_TIME(57.10) 6267 bytes
18
+ 0x19e3400 thread THREAD_STOPPED WAIT_FD(5) 10405 bytes
19
+ 0x19e0000 thread THREAD_STOPPED WAIT_NONE 14237 bytes
20
+ 0x19e0400 thread THREAD_STOPPED WAIT_NONE 14237 bytes
21
+ 0x19e0800 thread THREAD_STOPPED WAIT_NONE 14237 bytes
22
+ 0x19e0c00 thread THREAD_STOPPED WAIT_NONE 14237 bytes
23
+ 0x19de000 thread THREAD_STOPPED WAIT_NONE 14237 bytes
24
+ 0x19de400 thread THREAD_STOPPED WAIT_NONE 14237 bytes
25
+ 0x19de800 thread THREAD_STOPPED WAIT_NONE 14237 bytes
26
+ 0x19dec00 thread THREAD_STOPPED WAIT_NONE 14237 bytes
27
+ 0x19dc000 thread THREAD_STOPPED WAIT_NONE 14237 bytes
28
+ 0x19dc400 thread THREAD_STOPPED WAIT_NONE 14237 bytes
29
+ 0x19dc800 thread THREAD_STOPPED WAIT_NONE 14237 bytes
30
+ 0x19dcc00 thread THREAD_STOPPED WAIT_NONE 14237 bytes
31
+ 0x2266800 thread THREAD_STOPPED WAIT_NONE 14237 bytes
32
+ 0x1d63000 curr thread THREAD_RUNNABLE WAIT_NONE
33
+
34
+ (gdb) ruby threads
35
+ 0x1589000 main thread THREAD_STOPPED WAIT_JOIN(0x19ef400) 4417 bytes
36
+ node_call join in /usr/lib/ruby/gems/1.8/gems/god-0.7.13/bin/../lib/god.rb:626
37
+ node_call start in /usr/lib/ruby/gems/1.8/gems/god-0.7.13/bin/../lib/god.rb:633
38
+ node_call at_exit in /usr/lib/ruby/gems/1.8/gems/god-0.7.13/bin/../lib/god.rb:666
39
+ node_fcall (unknown) in /usr/lib/ruby/gems/1.8/gems/god-0.7.13/bin/../lib/god/cli/run.rb:87
40
+
41
+ 0x19ef400 thread THREAD_STOPPED WAIT_TIME(45.25) 6267 bytes
42
+ node_fcall sleep in /usr/lib/ruby/gems/1.8/gems/god-0.7.13/bin/../lib/god.rb:622
43
+ node_fcall start in /usr/lib/ruby/gems/1.8/gems/god-0.7.13/bin/../lib/god.rb:621
44
+ node_fcall loop in /usr/lib/ruby/gems/1.8/gems/god-0.7.13/bin/../lib/god.rb:621
45
+ node_call start in /usr/lib/ruby/gems/1.8/gems/god-0.7.13/bin/../lib/god.rb:620
46
+ node_call initialize in /usr/lib/ruby/gems/1.8/gems/god-0.7.13/bin/../lib/god.rb:620
47
+ node_call new in /usr/lib/ruby/gems/1.8/gems/god-0.7.13/bin/../lib/god.rb:620
48
+ node_call start in /usr/lib/ruby/gems/1.8/gems/god-0.7.13/bin/../lib/god.rb:633
49
+ node_call at_exit in /usr/lib/ruby/gems/1.8/gems/god-0.7.13/bin/../lib/god.rb:666
50
+ node_fcall (unknown) in /usr/lib/ruby/gems/1.8/gems/god-0.7.13/bin/../lib/god/cli/run.rb:87
51
+
52
+ 0x19e3400 thread THREAD_STOPPED WAIT_FD(5) 10405 bytes
53
+ node_call accept in /usr/lib/ruby/1.8/drb/unix.rb:98
54
+ node_call accept in /usr/lib/ruby/1.8/drb/drb.rb:1581
55
+ node_vcall main_loop in /usr/lib/ruby/1.8/drb/drb.rb:1430
56
+ node_call run in /usr/lib/ruby/1.8/drb/drb.rb:1427
57
+ node_call start in /usr/lib/ruby/1.8/drb/drb.rb:1427
58
+ node_vcall run in /usr/lib/ruby/1.8/drb/drb.rb:1347
59
+ node_call initialize in /usr/lib/ruby/1.8/drb/drb.rb:1627
60
+
61
+ (gdb) ruby threads trace
62
+ -- Tracing thread context switches.
63
+ 0x19ef400 thread THREAD_RUNNABLE WAIT_NONE 6267 bytes
64
+ 0x1d63000 thread THREAD_RUNNABLE WAIT_NONE 8623 bytes
65
+ 0x19e3400 thread THREAD_RUNNABLE WAIT_NONE 10405 bytes
66
+ 0x3001c00 thread THREAD_RUNNABLE WAIT_NONE 9507 bytes
67
+ 0x19e3400 thread THREAD_RUNNABLE WAIT_NONE 9507 bytes
68
+ 0x3001c00 thread THREAD_RUNNABLE WAIT_NONE 15059 bytes
69
+ 0x1d63000 thread THREAD_RUNNABLE WAIT_NONE 8623 bytes
70
+ 0x3001c00 thread THREAD_RUNNABLE WAIT_NONE 15059 bytes
71
+
72
+ (gdb) ruby trace 25
73
+ -- Tracing the next 25 ruby method calls.
74
+ handle_events in /usr/lib/ruby/gems/1.8/gems/god-0.7.13/bin/../lib/god/event_handler.rb:66
75
+ watching_pid? in /usr/lib/ruby/gems/1.8/gems/god-0.7.13/bin/../lib/god/event_handler.rb:58
76
+ [] in /usr/lib/ruby/gems/1.8/gems/god-0.7.13/bin/../lib/god/event_handler.rb:59
77
+ default in /usr/lib/ruby/gems/1.8/gems/god-0.7.13/bin/../lib/god/event_handler.rb:59
78
+ handle_events in /usr/lib/ruby/gems/1.8/gems/god-0.7.13/bin/../lib/god/event_handler.rb:66
79
+ watching_pid? in /usr/lib/ruby/gems/1.8/gems/god-0.7.13/bin/../lib/god/event_handler.rb:58
80
+ [] in /usr/lib/ruby/gems/1.8/gems/god-0.7.13/bin/../lib/god/event_handler.rb:59
81
+ default in /usr/lib/ruby/gems/1.8/gems/god-0.7.13/bin/../lib/god/event_handler.rb:59
82
+ handle_events in /usr/lib/ruby/gems/1.8/gems/god-0.7.13/bin/../lib/god/event_handler.rb:66
83
+ watching_pid? in /usr/lib/ruby/gems/1.8/gems/god-0.7.13/bin/../lib/god/event_handler.rb:58
84
+ [] in /usr/lib/ruby/gems/1.8/gems/god-0.7.13/bin/../lib/god/event_handler.rb:59
85
+ default in /usr/lib/ruby/gems/1.8/gems/god-0.7.13/bin/../lib/god/event_handler.rb:59
86
+ handle_events in /usr/lib/ruby/gems/1.8/gems/god-0.7.13/bin/../lib/god/event_handler.rb:66
87
+ handle_events in /usr/lib/ruby/gems/1.8/gems/god-0.7.13/bin/../lib/god/event_handler.rb:66
88
+ handle_events in /usr/lib/ruby/gems/1.8/gems/god-0.7.13/bin/../lib/god/event_handler.rb:66
89
+ handle_events in /usr/lib/ruby/gems/1.8/gems/god-0.7.13/bin/../lib/god/event_handler.rb:66
90
+ handle_events in /usr/lib/ruby/gems/1.8/gems/god-0.7.13/bin/../lib/god/event_handler.rb:66
91
+ handle_events in /usr/lib/ruby/gems/1.8/gems/god-0.7.13/bin/../lib/god/event_handler.rb:66
92
+ handle_events in /usr/lib/ruby/gems/1.8/gems/god-0.7.13/bin/../lib/god/event_handler.rb:66
93
+ handle_events in /usr/lib/ruby/gems/1.8/gems/god-0.7.13/bin/../lib/god/event_handler.rb:66
94
+ handle_events in /usr/lib/ruby/gems/1.8/gems/god-0.7.13/bin/../lib/god/event_handler.rb:66
95
+ watching_pid? in /usr/lib/ruby/gems/1.8/gems/god-0.7.13/bin/../lib/god/event_handler.rb:58
96
+ [] in /usr/lib/ruby/gems/1.8/gems/god-0.7.13/bin/../lib/god/event_handler.rb:59
97
+ default in /usr/lib/ruby/gems/1.8/gems/god-0.7.13/bin/../lib/god/event_handler.rb:59
98
+ handle_events in /usr/lib/ruby/gems/1.8/gems/god-0.7.13/bin/../lib/god/event_handler.rb:66
99
+
100
+ (gdb) ruby objects
101
+
102
+ HEAPS 8
103
+ SLOTS 1686252
104
+ LIVE 893327 (52.98%)
105
+ FREE 792925 (47.02%)
106
+
107
+ bignum 2 (0.00%)
108
+ file 51 (0.01%)
109
+ float 77 (0.01%)
110
+ module 781 (0.09%)
111
+ varmap 1354 (0.15%)
112
+ scope 1641 (0.18%)
113
+ match 1676 (0.19%)
114
+ iclass 1744 (0.20%)
115
+ regexp 2255 (0.25%)
116
+ data 3539 (0.40%)
117
+ class 3680 (0.41%)
118
+ hash 6196 (0.69%)
119
+ object 8785 (0.98%)
120
+ array 13850 (1.55%)
121
+ string 105350 (11.79%)
122
+ node 742346 (83.10%)
123
+
124
+ (gdb) ruby objects classes
125
+ 1 YAML::Syck::Resolver
126
+ 1 YAML::Syck::Resolver
127
+ 1 SystemStackError
128
+ 1 Object
129
+ 1 Object
130
+ 1 NoMemoryError
131
+ 1 fatal
132
+ 1 Object
133
+ 1 Gem::SourceIndex
134
+ 1 Gem::GemPathSearcher
135
+ 1 Gem::ConfigFile
136
+ 1 God::Logger
137
+ 1 God::SimpleLogger
138
+ 1 God::CLI::Run
139
+ 1 DRb::DRbServer::InvokeMethod
140
+ 1 DRb::DRbServer
141
+ 1 DRb::DRbIdConv
142
+ 1 God::Registry
143
+ 1 OptionParser::Switch::OptionalArgument
144
+ 1 OptionParser
145
+ 1 God::Socket
146
+ 1 God::Contacts::Email
147
+ 2 Date::Infinity
148
+ 2 DRb::DRbMessage
149
+ 2 DRb::DRbBadScheme
150
+ 2 DRb::DRbUNIXSocket
151
+ 3 OptionParser::List
152
+ 6 IOError
153
+ 6 Errno::ESRCH
154
+ 6 OptionParser::Switch::RequiredArgument
155
+ 6 Net::InternetMessageIO
156
+ 7 God::System::SlashProcPoller
157
+ 7 God::System::Process
158
+ 7 God::DriverOperation
159
+ 7 Net::SMTP
160
+ 8 StandardError
161
+ 10 OptionParser::Switch::NoArgument
162
+ 13 God::Conditions::Flapping
163
+ 13 God::Conditions::ProcessExits
164
+ 13 God::Behaviors::CleanPidFile
165
+ 13 God::Process
166
+ 13 God::Watch
167
+ 13 God::Driver
168
+ 13 God::DriverEventQueue
169
+ 19 God::DriverEvent
170
+ 38 Process::Status
171
+ 39 God::Conditions::ProcessRunning
172
+ 50 Range
173
+ 63 Gem::Specification
174
+ 65 God::Metric
175
+ 81 Gem::Dependency
176
+ 174 Gem::Version::Part
177
+ 209 Gem::Requirement
178
+ 219 Gem::Version
179
+
180
+ (gdb) ruby objects strings
181
+ 70 u'bin'
182
+ 73 u' INFO'
183
+ 74 u'--main'
184
+ 74 u'I'
185
+ 75 u'..'
186
+ 78 u'ruby'
187
+ 80 u'::'
188
+ 92 u'1.3.2'
189
+ 100 u'README.rdoc'
190
+ 102 u' '
191
+ 108 u'Rakefile'
192
+ 110 u'README'
193
+ 114 u'\r\n'
194
+ 127 u'>='
195
+ 140 u'lib'
196
+ 158 u'0'
197
+ 294 u'\n'
198
+ 619 u''
199
+
200
+ 30503 unique strings
201
+ 3187435 bytes
202
+
203
+ (gdb) ruby objects nodes
204
+ 8156 NODE_EVSTR
205
+ 8966 NODE_COLON2
206
+ 10020 NODE_DVAR
207
+ 11493 NODE_AND
208
+ 13157 NODE_FCALL
209
+ 14493 NODE_VCALL
210
+ 15148 NODE_ARGS
211
+ 15180 NODE_CONST
212
+ 15445 NODE_SCOPE
213
+ 16582 NODE_IF
214
+ 21594 NODE_LASGN
215
+ 22084 NODE_METHOD
216
+ 26633 NODE_STR
217
+ 37819 NODE_LIT
218
+ 64325 NODE_LVAR
219
+ 64470 NODE_NEWLINE
220
+ 69436 NODE_BLOCK
221
+ 85825 NODE_CALL
222
+ 126739 NODE_ARRAY
223
+
224
+ === TODO
225
+
226
+ `ruby where` for the current stack trace
227
+ `ruby print` to inspect ruby variables
228
+ `ruby breakpoint` to breakpoint on ruby methods
229
+ `ruby irb` for a simple interactive shell
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rbconfig'
3
+
4
+ if ARGV.size == 1 and ARGV[0] =~ /^\d+$/
5
+ ARGV.unshift "#{Config::CONFIG['bindir']}/ruby"
6
+ elsif ARGV.size == 2 and File.exist?(ARGV[0]) and ARGV[1] =~ /^\d+$/
7
+ else
8
+ puts "Usage:"
9
+ puts
10
+ puts " gdb.rb <pid>"
11
+ puts " gdb.rb <path to ruby> <pid>"
12
+ puts
13
+ exit(1)
14
+ end
15
+
16
+ cmd = "#{File.dirname(__FILE__)}/../ext/dst/bin/gdb -ex 'py execfile(\"#{File.dirname(__FILE__)}/../scripts/ruby-gdb.py\")' #{ARGV.join(" ")}"
17
+ exec(cmd)
@@ -0,0 +1,2 @@
1
+ default:
2
+ install:
@@ -0,0 +1,71 @@
1
+ CWD = File.expand_path(File.dirname(__FILE__))
2
+
3
+ def sys(cmd)
4
+ puts " -- #{cmd}"
5
+ unless ret = xsystem(cmd)
6
+ raise "#{cmd} failed, please report to gdb@tmm1.net with pastie.org link to #{CWD}/mkmf.log and #{CWD}/src/gdb-7.0/config.log"
7
+ end
8
+ ret
9
+ end
10
+
11
+ require 'mkmf'
12
+ require 'fileutils'
13
+
14
+ if RUBY_VERSION >= "1.9"
15
+ STDERR.puts "\n\n"
16
+ STDERR.puts "***************************************************************************************"
17
+ STDERR.puts "************************** ruby 1.9 is not supported (yet) =( *************************"
18
+ STDERR.puts "***************************************************************************************"
19
+ exit(1)
20
+ end
21
+
22
+ if `uname -a 2>&1` !~ /x86_64/
23
+ STDERR.puts "\n\n"
24
+ STDERR.puts "***************************************************************************************"
25
+ STDERR.puts "********************* Only x86_64 linux is supported (for now) =( *********************"
26
+ STDERR.puts "***************************************************************************************"
27
+ exit(1)
28
+ end
29
+
30
+ unless have_header('python2.5/Python.h') or have_header('python2.6/Python.h')
31
+ STDERR.puts "\n\n"
32
+ STDERR.puts "***************************************************************************************"
33
+ STDERR.puts "***************** Python required (apt-get install python2.5-dev) =( ******************"
34
+ STDERR.puts "***************************************************************************************"
35
+ exit(1)
36
+ end
37
+
38
+ gdb = File.basename('gdb-7.0.tar.bz2')
39
+ dir = File.basename(gdb, '.tar.bz2')
40
+
41
+ puts "(I'm about to compile gdb7.. this will definitely take a while)"
42
+
43
+ Dir.chdir('src') do
44
+ FileUtils.rm_rf(dir) if File.exists?(dir)
45
+
46
+ sys("tar jxvf #{gdb}")
47
+ Dir.chdir(dir+"/gdb") do
48
+ if ENV['DEV']
49
+ sys("git init")
50
+ sys("git add .")
51
+ sys("git commit -m 'initial source'")
52
+ end
53
+
54
+ %w[
55
+ gdb-eval
56
+ gdb-breakpoints
57
+ gdb-leak
58
+ ].each do |patch|
59
+ sys("patch -p1 < ../../../../patches/#{patch}.patch")
60
+ sys("git commit -am '#{patch}'") if ENV['DEV']
61
+ end
62
+ end
63
+
64
+ Dir.chdir(dir) do
65
+ sys("./configure --prefix=#{CWD}/dst/")
66
+ sys("make")
67
+ sys("make install")
68
+ end
69
+ end
70
+
71
+ FileUtils.touch 'Makefile'
Binary file
@@ -0,0 +1,32 @@
1
+ spec = Gem::Specification.new do |s|
2
+ s.name = 'gdb.rb'
3
+ s.version = '0.1.0'
4
+ s.date = '2009-11-02'
5
+ s.rubyforge_project = 'gdb-rb'
6
+ s.summary = 'gdb hooks for MRI'
7
+ s.description = 'A set of gdb7 extensions for the MRI interpreter'
8
+
9
+ s.homepage = "http://github.com/tmm1/gdb.rb"
10
+
11
+ s.authors = ["Aman Gupta"]
12
+ s.email = "gdb@tmm1.net"
13
+
14
+ s.has_rdoc = false
15
+ s.extensions = 'ext/extconf.rb'
16
+ s.bindir = 'bin'
17
+ s.executables << 'gdb.rb'
18
+
19
+ # ruby -rpp -e' pp `git ls-files`.split("\n").sort '
20
+ s.files = [
21
+ "README",
22
+ "bin/gdb.rb",
23
+ "ext/extconf.rb",
24
+ "ext/Makefile",
25
+ "ext/src/gdb-7.0.tar.bz2",
26
+ "patches/gdb-eval.patch",
27
+ "patches/gdb-breakpoints.patch",
28
+ "patches/gdb-leak.patch",
29
+ "scripts/ruby-gdb.py",
30
+ "gdb.rb.gemspec"
31
+ ]
32
+ end
@@ -0,0 +1,744 @@
1
+ diff --git a/Makefile.in b/Makefile.in
2
+ index 7d53205..ed6729e 100644
3
+ --- a/Makefile.in
4
+ +++ b/Makefile.in
5
+ @@ -267,6 +267,7 @@ SUBDIR_TUI_CFLAGS= \
6
+ #
7
+ SUBDIR_PYTHON_OBS = \
8
+ python.o \
9
+ + py-breakpoint.o \
10
+ py-cmd.o \
11
+ py-frame.o \
12
+ py-function.o \
13
+ @@ -277,6 +278,7 @@ SUBDIR_PYTHON_OBS = \
14
+ py-value.o
15
+ SUBDIR_PYTHON_SRCS = \
16
+ python/python.c \
17
+ + python/py-breakpoint.c \
18
+ python/py-cmd.c \
19
+ python/py-frame.c \
20
+ python/py-function.c \
21
+ @@ -1963,6 +1965,10 @@ python.o: $(srcdir)/python/python.c
22
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/python.c
23
+ $(POSTCOMPILE)
24
+
25
+ +py-breakpoint.o: $(srcdir)/python/py-breakpoint.c
26
+ + $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-breakpoint.c
27
+ + $(POSTCOMPILE)
28
+ +
29
+ py-cmd.o: $(srcdir)/python/py-cmd.c
30
+ $(COMPILE) $(PYTHON_CFLAGS) $(srcdir)/python/py-cmd.c
31
+ $(POSTCOMPILE)
32
+ diff --git a/python/py-breakpoint.c b/python/py-breakpoint.c
33
+ new file mode 100644
34
+ index 0000000..913deec
35
+ --- /dev/null
36
+ +++ b/python/py-breakpoint.c
37
+ @@ -0,0 +1,665 @@
38
+ +/* Python interface to breakpoints
39
+ +
40
+ + Copyright (C) 2008, 2009 Free Software Foundation, Inc.
41
+ +
42
+ + This file is part of GDB.
43
+ +
44
+ + This program is free software; you can redistribute it and/or modify
45
+ + it under the terms of the GNU General Public License as published by
46
+ + the Free Software Foundation; either version 3 of the License, or
47
+ + (at your option) any later version.
48
+ +
49
+ + This program is distributed in the hope that it will be useful,
50
+ + but WITHOUT ANY WARRANTY; without even the implied warranty of
51
+ + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
52
+ + GNU General Public License for more details.
53
+ +
54
+ + You should have received a copy of the GNU General Public License
55
+ + along with this program. If not, see <http://www.gnu.org/licenses/>. */
56
+ +
57
+ +#include "defs.h"
58
+ +#include "value.h"
59
+ +#include "exceptions.h"
60
+ +#include "python-internal.h"
61
+ +#include "charset.h"
62
+ +#include "breakpoint.h"
63
+ +#include "gdbcmd.h"
64
+ +#include "gdbthread.h"
65
+ +#include "observer.h"
66
+ +#include "arch-utils.h"
67
+ +#include "language.h"
68
+ +
69
+ +/* From breakpoint.c. */
70
+ +extern struct breakpoint *breakpoint_chain;
71
+ +
72
+ +
73
+ +typedef struct breakpoint_object breakpoint_object;
74
+ +
75
+ +static PyTypeObject breakpoint_object_type;
76
+ +
77
+ +/* A dynamically allocated vector of breakpoint objects. Each
78
+ + breakpoint has a number. A breakpoint is valid if its slot in this
79
+ + vector is non-null. When a breakpoint is deleted, we drop our
80
+ + reference to it and zero its slot; this is how we let the Python
81
+ + object have a lifetime which is independent from that of the gdb
82
+ + breakpoint. */
83
+ +static breakpoint_object **bppy_breakpoints;
84
+ +
85
+ +/* Number of slots in bppy_breakpoints. */
86
+ +static int bppy_slots;
87
+ +
88
+ +/* Number of live breakpoints. */
89
+ +static int bppy_live;
90
+ +
91
+ +/* Variables used to pass information between the Breakpoint
92
+ + constructor and the breakpoint-created hook function. */
93
+ +static breakpoint_object *bppy_pending_object;
94
+ +
95
+ +struct breakpoint_object
96
+ +{
97
+ + PyObject_HEAD
98
+ +
99
+ + /* The breakpoint number according to gdb. */
100
+ + int number;
101
+ +
102
+ + /* The gdb breakpoint object, or NULL if the breakpoint has been
103
+ + deleted. */
104
+ + struct breakpoint *bp;
105
+ +};
106
+ +
107
+ +/* Evaluate to true if the breakpoint NUM is valid, false otherwise. */
108
+ +#define BPPY_VALID_P(Num) \
109
+ + ((Num) >= 0 \
110
+ + && (Num) < bppy_slots \
111
+ + && bppy_breakpoints[Num] != NULL)
112
+ +
113
+ +/* Require that BREAKPOINT be a valid breakpoint ID; throw a Python
114
+ + exception if it is invalid. */
115
+ +#define BPPY_REQUIRE_VALID(Breakpoint) \
116
+ + do { \
117
+ + if (! BPPY_VALID_P ((Breakpoint)->number)) \
118
+ + return PyErr_Format (PyExc_RuntimeError, "breakpoint %d is invalid", \
119
+ + (Breakpoint)->number); \
120
+ + } while (0)
121
+ +
122
+ +/* Require that BREAKPOINT be a valid breakpoint ID; throw a Python
123
+ + exception if it is invalid. This macro is for use in setter functions. */
124
+ +#define BPPY_SET_REQUIRE_VALID(Breakpoint) \
125
+ + do { \
126
+ + if (! BPPY_VALID_P ((Breakpoint)->number)) \
127
+ + { \
128
+ + PyErr_Format (PyExc_RuntimeError, "breakpoint %d is invalid", \
129
+ + (Breakpoint)->number); \
130
+ + return -1; \
131
+ + } \
132
+ + } while (0)
133
+ +
134
+ +/* Python function which checks the validity of a breakpoint object. */
135
+ +static PyObject *
136
+ +bppy_is_valid (PyObject *self, PyObject *args)
137
+ +{
138
+ + if (((breakpoint_object *) self)->bp)
139
+ + Py_RETURN_TRUE;
140
+ + Py_RETURN_FALSE;
141
+ +}
142
+ +
143
+ +/* Python function to test whether or not the breakpoint is enabled. */
144
+ +static PyObject *
145
+ +bppy_get_enabled (PyObject *self, void *closure)
146
+ +{
147
+ + if (! ((breakpoint_object *) self)->bp)
148
+ + Py_RETURN_FALSE;
149
+ + /* Not clear what we really want here. */
150
+ + if (((breakpoint_object *) self)->bp->enable_state == bp_enabled)
151
+ + Py_RETURN_TRUE;
152
+ + Py_RETURN_FALSE;
153
+ +}
154
+ +
155
+ +/* Python function to test whether or not the breakpoint is silent. */
156
+ +static PyObject *
157
+ +bppy_get_silent (PyObject *self, void *closure)
158
+ +{
159
+ + BPPY_REQUIRE_VALID ((breakpoint_object *) self);
160
+ + if (((breakpoint_object *) self)->bp->silent)
161
+ + Py_RETURN_TRUE;
162
+ + Py_RETURN_FALSE;
163
+ +}
164
+ +
165
+ +/* Python function to set the enabled state of a breakpoint. */
166
+ +static int
167
+ +bppy_set_enabled (PyObject *self, PyObject *newvalue, void *closure)
168
+ +{
169
+ + breakpoint_object *self_bp = (breakpoint_object *) self;
170
+ + int cmp;
171
+ +
172
+ + BPPY_SET_REQUIRE_VALID (self_bp);
173
+ +
174
+ + if (newvalue == NULL)
175
+ + {
176
+ + PyErr_SetString (PyExc_TypeError, "cannot delete `enabled' attribute");
177
+ + return -1;
178
+ + }
179
+ + else if (! PyBool_Check (newvalue))
180
+ + {
181
+ + PyErr_SetString (PyExc_TypeError,
182
+ + "the value of `enabled' must be a boolean");
183
+ + return -1;
184
+ + }
185
+ +
186
+ + cmp = PyObject_IsTrue (newvalue);
187
+ + if (cmp < 0)
188
+ + return -1;
189
+ + else if (cmp == 1)
190
+ + enable_breakpoint (self_bp->bp);
191
+ + else
192
+ + disable_breakpoint (self_bp->bp);
193
+ + return 0;
194
+ +}
195
+ +
196
+ +/* Python function to set the 'silent' state of a breakpoint. */
197
+ +static int
198
+ +bppy_set_silent (PyObject *self, PyObject *newvalue, void *closure)
199
+ +{
200
+ + breakpoint_object *self_bp = (breakpoint_object *) self;
201
+ + int cmp;
202
+ +
203
+ + BPPY_SET_REQUIRE_VALID (self_bp);
204
+ +
205
+ + if (newvalue == NULL)
206
+ + {
207
+ + PyErr_SetString (PyExc_TypeError, "cannot delete `silent' attribute");
208
+ + return -1;
209
+ + }
210
+ + else if (! PyBool_Check (newvalue))
211
+ + {
212
+ + PyErr_SetString (PyExc_TypeError,
213
+ + "the value of `silent' must be a boolean");
214
+ + return -1;
215
+ + }
216
+ +
217
+ + cmp = PyObject_IsTrue (newvalue);
218
+ + if (cmp < 0)
219
+ + return -1;
220
+ + else
221
+ + self_bp->bp->silent = cmp;
222
+ +
223
+ + return 0;
224
+ +}
225
+ +
226
+ +/* Python function to set the thread of a breakpoint. */
227
+ +static int
228
+ +bppy_set_thread (PyObject *self, PyObject *newvalue, void *closure)
229
+ +{
230
+ + breakpoint_object *self_bp = (breakpoint_object *) self;
231
+ + int id;
232
+ +
233
+ + BPPY_SET_REQUIRE_VALID (self_bp);
234
+ +
235
+ + if (newvalue == NULL)
236
+ + {
237
+ + PyErr_SetString (PyExc_TypeError, "cannot delete `thread' attribute");
238
+ + return -1;
239
+ + }
240
+ + else if (PyInt_Check (newvalue))
241
+ + {
242
+ + id = (int) PyInt_AsLong (newvalue);
243
+ + if (! valid_thread_id (id))
244
+ + {
245
+ + PyErr_SetString (PyExc_RuntimeError, "invalid thread id");
246
+ + return -1;
247
+ + }
248
+ + }
249
+ + else if (newvalue == Py_None)
250
+ + id = -1;
251
+ + else
252
+ + {
253
+ + PyErr_SetString (PyExc_TypeError,
254
+ + "the value of `thread' must be an integer or None");
255
+ + return -1;
256
+ + }
257
+ +
258
+ + self_bp->bp->thread = id;
259
+ +
260
+ + return 0;
261
+ +}
262
+ +
263
+ +/* Python function to set the ignore count of a breakpoint. */
264
+ +static int
265
+ +bppy_set_ignore_count (PyObject *self, PyObject *newvalue, void *closure)
266
+ +{
267
+ + breakpoint_object *self_bp = (breakpoint_object *) self;
268
+ + long value;
269
+ +
270
+ + BPPY_SET_REQUIRE_VALID (self_bp);
271
+ +
272
+ + if (newvalue == NULL)
273
+ + {
274
+ + PyErr_SetString (PyExc_TypeError,
275
+ + "cannot delete `ignore_count' attribute");
276
+ + return -1;
277
+ + }
278
+ + else if (! PyInt_Check (newvalue))
279
+ + {
280
+ + PyErr_SetString (PyExc_TypeError,
281
+ + "the value of `ignore_count' must be an integer");
282
+ + return -1;
283
+ + }
284
+ +
285
+ + value = PyInt_AsLong (newvalue);
286
+ + if (value < 0)
287
+ + value = 0;
288
+ + set_ignore_count (self_bp->number, (int) value, 0);
289
+ +
290
+ + return 0;
291
+ +}
292
+ +
293
+ +/* Python function to set the hit count of a breakpoint. */
294
+ +static int
295
+ +bppy_set_hit_count (PyObject *self, PyObject *newvalue, void *closure)
296
+ +{
297
+ + breakpoint_object *self_bp = (breakpoint_object *) self;
298
+ +
299
+ + BPPY_SET_REQUIRE_VALID (self_bp);
300
+ +
301
+ + if (newvalue == NULL)
302
+ + {
303
+ + PyErr_SetString (PyExc_TypeError, "cannot delete `hit_count' attribute");
304
+ + return -1;
305
+ + }
306
+ + else if (! PyInt_Check (newvalue) || PyInt_AsLong (newvalue) != 0)
307
+ + {
308
+ + PyErr_SetString (PyExc_AttributeError,
309
+ + "the value of `hit_count' must be zero");
310
+ + return -1;
311
+ + }
312
+ +
313
+ + self_bp->bp->hit_count = 0;
314
+ +
315
+ + return 0;
316
+ +}
317
+ +
318
+ +/* Python function to get the location of a breakpoint. */
319
+ +static PyObject *
320
+ +bppy_get_location (PyObject *self, void *closure)
321
+ +{
322
+ + char *str;
323
+ +
324
+ + BPPY_REQUIRE_VALID ((breakpoint_object *) self);
325
+ + str = ((breakpoint_object *) self)->bp->addr_string;
326
+ + /* FIXME: watchpoints? tracepoints? */
327
+ + if (! str)
328
+ + str = "";
329
+ + return PyString_Decode (str, strlen (str), host_charset (), NULL);
330
+ +}
331
+ +
332
+ +// /* Python function to get the condition expression of a breakpoint. */
333
+ +// static PyObject *
334
+ +// bppy_get_condition (PyObject *self, void *closure)
335
+ +// {
336
+ +// char *str;
337
+ +// BPPY_REQUIRE_VALID ((breakpoint_object *) self);
338
+ +//
339
+ +// str = ((breakpoint_object *) self)->bp->cond_string;
340
+ +// if (! str)
341
+ +// Py_RETURN_NONE;
342
+ +// return PyString_Decode (str, strlen (str), host_charset (), NULL);
343
+ +// }
344
+ +
345
+ +// static int
346
+ +// bppy_set_condition (PyObject *self, PyObject *newvalue, void *closure)
347
+ +// {
348
+ +// char *exp;
349
+ +// breakpoint_object *self_bp = (breakpoint_object *) self;
350
+ +// volatile struct gdb_exception except;
351
+ +//
352
+ +// BPPY_SET_REQUIRE_VALID (self_bp);
353
+ +//
354
+ +// if (newvalue == NULL)
355
+ +// {
356
+ +// PyErr_SetString (PyExc_TypeError, "cannot delete `condition' attribute");
357
+ +// return -1;
358
+ +// }
359
+ +// else if (newvalue == Py_None)
360
+ +// exp = "";
361
+ +// else
362
+ +// {
363
+ +// exp = python_string_to_host_string (newvalue);
364
+ +// if (exp == NULL)
365
+ +// return -1;
366
+ +// }
367
+ +//
368
+ +// TRY_CATCH (except, RETURN_MASK_ALL)
369
+ +// {
370
+ +// set_breakpoint_condition (self_bp->bp, exp, 0);
371
+ +// }
372
+ +// GDB_PY_HANDLE_EXCEPTION (except);
373
+ +//
374
+ +// return 0;
375
+ +// }
376
+ +
377
+ +/* Python function to get the commands attached to a breakpoint. */
378
+ +static PyObject *
379
+ +bppy_get_commands (PyObject *self, void *closure)
380
+ +{
381
+ + breakpoint_object *self_bp = (breakpoint_object *) self;
382
+ + long length;
383
+ + volatile struct gdb_exception except;
384
+ + struct ui_file *string_file;
385
+ + struct cleanup *chain;
386
+ + PyObject *result;
387
+ + char *cmdstr;
388
+ +
389
+ + BPPY_REQUIRE_VALID (self_bp);
390
+ +
391
+ + if (! self_bp->bp->commands)
392
+ + Py_RETURN_NONE;
393
+ +
394
+ + string_file = mem_fileopen ();
395
+ + chain = make_cleanup_ui_file_delete (string_file);
396
+ +
397
+ + TRY_CATCH (except, RETURN_MASK_ALL)
398
+ + {
399
+ + /* FIXME: this can fail. Maybe we need to be making a new
400
+ + ui_out object here? */
401
+ + ui_out_redirect (uiout, string_file);
402
+ + print_command_lines (uiout, self_bp->bp->commands, 0);
403
+ + ui_out_redirect (uiout, NULL);
404
+ + }
405
+ + cmdstr = ui_file_xstrdup (string_file, &length);
406
+ + GDB_PY_HANDLE_EXCEPTION (except);
407
+ +
408
+ + result = PyString_Decode (cmdstr, strlen (cmdstr), host_charset (), NULL);
409
+ + do_cleanups (chain);
410
+ + xfree (cmdstr);
411
+ + return result;
412
+ +}
413
+ +
414
+ +/* Python function to get the breakpoint's number. */
415
+ +static PyObject *
416
+ +bppy_get_number (PyObject *self, void *closure)
417
+ +{
418
+ + breakpoint_object *self_bp = (breakpoint_object *) self;
419
+ +
420
+ + BPPY_REQUIRE_VALID (self_bp);
421
+ +
422
+ + return PyInt_FromLong (self_bp->number);
423
+ +}
424
+ +
425
+ +/* Python function to get the breakpoint's thread ID. */
426
+ +static PyObject *
427
+ +bppy_get_thread (PyObject *self, void *closure)
428
+ +{
429
+ + breakpoint_object *self_bp = (breakpoint_object *) self;
430
+ +
431
+ + BPPY_REQUIRE_VALID (self_bp);
432
+ +
433
+ + if (self_bp->bp->thread == -1)
434
+ + Py_RETURN_NONE;
435
+ +
436
+ + return PyInt_FromLong (self_bp->bp->thread);
437
+ +}
438
+ +
439
+ +/* Python function to get the breakpoint's hit count. */
440
+ +static PyObject *
441
+ +bppy_get_hit_count (PyObject *self, void *closure)
442
+ +{
443
+ + breakpoint_object *self_bp = (breakpoint_object *) self;
444
+ +
445
+ + BPPY_REQUIRE_VALID (self_bp);
446
+ +
447
+ + return PyInt_FromLong (self_bp->bp->hit_count);
448
+ +}
449
+ +
450
+ +/* Python function to get the breakpoint's ignore count. */
451
+ +static PyObject *
452
+ +bppy_get_ignore_count (PyObject *self, void *closure)
453
+ +{
454
+ + breakpoint_object *self_bp = (breakpoint_object *) self;
455
+ +
456
+ + BPPY_REQUIRE_VALID (self_bp);
457
+ +
458
+ + return PyInt_FromLong (self_bp->bp->ignore_count);
459
+ +}
460
+ +
461
+ +/* Python function to create a new breakpoint. */
462
+ +static PyObject *
463
+ +bppy_new (PyTypeObject *subtype, PyObject *args, PyObject *kwargs)
464
+ +{
465
+ + PyObject *result;
466
+ + char *spec;
467
+ + volatile struct gdb_exception except;
468
+ +
469
+ + /* FIXME: allow condition, thread, temporary, ... ? */
470
+ + if (! PyArg_ParseTuple (args, "s", &spec))
471
+ + return NULL;
472
+ + result = subtype->tp_alloc (subtype, 0);
473
+ + if (! result)
474
+ + return NULL;
475
+ + bppy_pending_object = (breakpoint_object *) result;
476
+ + bppy_pending_object->number = -1;
477
+ + bppy_pending_object->bp = NULL;
478
+ +
479
+ + TRY_CATCH (except, RETURN_MASK_ALL)
480
+ + {
481
+ + set_breakpoint (python_gdbarch, spec, NULL, 0, 0, -1, 0,
482
+ + AUTO_BOOLEAN_TRUE, 1);
483
+ + }
484
+ + if (except.reason < 0)
485
+ + {
486
+ + subtype->tp_free (result);
487
+ + return PyErr_Format (except.reason == RETURN_QUIT
488
+ + ? PyExc_KeyboardInterrupt : PyExc_RuntimeError,
489
+ + "%s", except.message);
490
+ + }
491
+ +
492
+ + BPPY_REQUIRE_VALID ((breakpoint_object *) result);
493
+ + return result;
494
+ +}
495
+ +
496
+ +
497
+ +
498
+ +/* Static function to return a tuple holding all breakpoints. */
499
+ +
500
+ +PyObject *
501
+ +gdbpy_breakpoints (PyObject *self, PyObject *args)
502
+ +{
503
+ + PyObject *result;
504
+ +
505
+ + if (bppy_live == 0)
506
+ + Py_RETURN_NONE;
507
+ +
508
+ + result = PyTuple_New (bppy_live);
509
+ + if (result)
510
+ + {
511
+ + int i, out = 0;
512
+ + for (i = 0; out < bppy_live; ++i)
513
+ + {
514
+ + if (! bppy_breakpoints[i])
515
+ + continue;
516
+ + Py_INCREF (bppy_breakpoints[i]);
517
+ + PyTuple_SetItem (result, out, (PyObject *) bppy_breakpoints[i]);
518
+ + ++out;
519
+ + }
520
+ + }
521
+ + return result;
522
+ +}
523
+ +
524
+ +
525
+ +
526
+ +/* Event callback functions. */
527
+ +
528
+ +/* Callback that is used when a breakpoint is created. This function
529
+ + will create a new Python breakpoint object. */
530
+ +static void
531
+ +gdbpy_breakpoint_created (int num)
532
+ +{
533
+ + breakpoint_object *newbp;
534
+ + struct breakpoint *bp;
535
+ + struct cleanup *cleanup;
536
+ +
537
+ + if (num < 0)
538
+ + return;
539
+ +
540
+ + for (bp = breakpoint_chain; bp; bp = bp->next)
541
+ + if (bp->number == num)
542
+ + break;
543
+ + if (! bp)
544
+ + return;
545
+ +
546
+ + if (num >= bppy_slots)
547
+ + {
548
+ + int old = bppy_slots;
549
+ + bppy_slots = bppy_slots * 2 + 10;
550
+ + bppy_breakpoints
551
+ + = (breakpoint_object **) xrealloc (bppy_breakpoints,
552
+ + (bppy_slots
553
+ + * sizeof (breakpoint_object *)));
554
+ + memset (&bppy_breakpoints[old], 0,
555
+ + (bppy_slots - old) * sizeof (PyObject *));
556
+ + }
557
+ +
558
+ + ++bppy_live;
559
+ +
560
+ + cleanup = ensure_python_env (get_current_arch (), current_language);
561
+ +
562
+ + if (bppy_pending_object)
563
+ + {
564
+ + newbp = bppy_pending_object;
565
+ + bppy_pending_object = NULL;
566
+ + }
567
+ + else
568
+ + newbp = PyObject_New (breakpoint_object, &breakpoint_object_type);
569
+ + if (newbp)
570
+ + {
571
+ + // PyObject *hookfn;
572
+ +
573
+ + newbp->number = num;
574
+ + newbp->bp = bp;
575
+ + bppy_breakpoints[num] = newbp;
576
+ +
577
+ + // hookfn = gdbpy_get_hook_function ("new_breakpoint");
578
+ + // if (hookfn)
579
+ + // {
580
+ + // PyObject *result;
581
+ + // result = PyObject_CallFunctionObjArgs (hookfn, newbp, NULL);
582
+ + // if (result)
583
+ + // {
584
+ + // Py_DECREF (result);
585
+ + // }
586
+ + // Py_DECREF (hookfn);
587
+ + // }
588
+ + }
589
+ +
590
+ + /* Just ignore errors here. */
591
+ + PyErr_Clear ();
592
+ +
593
+ + do_cleanups (cleanup);
594
+ +}
595
+ +
596
+ +/* Callback that is used when a breakpoint is deleted. This will
597
+ + invalidate the corresponding Python object. */
598
+ +static void
599
+ +gdbpy_breakpoint_deleted (int num)
600
+ +{
601
+ + struct cleanup *cleanup;
602
+ +
603
+ + cleanup = ensure_python_env (get_current_arch (), current_language);
604
+ + if (BPPY_VALID_P (num))
605
+ + {
606
+ + bppy_breakpoints[num]->bp = NULL;
607
+ + Py_DECREF (bppy_breakpoints[num]);
608
+ + bppy_breakpoints[num] = NULL;
609
+ + --bppy_live;
610
+ + }
611
+ + do_cleanups (cleanup);
612
+ +}
613
+ +
614
+ +
615
+ +
616
+ +/* Initialize the Python breakpoint code. */
617
+ +void
618
+ +gdbpy_initialize_breakpoints (void)
619
+ +{
620
+ + breakpoint_object_type.tp_new = bppy_new;
621
+ + if (PyType_Ready (&breakpoint_object_type) < 0)
622
+ + return;
623
+ +
624
+ + Py_INCREF (&breakpoint_object_type);
625
+ + PyModule_AddObject (gdb_module, "Breakpoint",
626
+ + (PyObject *) &breakpoint_object_type);
627
+ +
628
+ + observer_attach_breakpoint_created (gdbpy_breakpoint_created);
629
+ + observer_attach_breakpoint_deleted (gdbpy_breakpoint_deleted);
630
+ +}
631
+ +
632
+ +
633
+ +
634
+ +static PyGetSetDef breakpoint_object_getset[] = {
635
+ + { "enabled", bppy_get_enabled, bppy_set_enabled,
636
+ + "Boolean telling whether the breakpoint is enabled.", NULL },
637
+ + { "silent", bppy_get_silent, bppy_set_silent,
638
+ + "Boolean telling whether the breakpoint is silent.", NULL },
639
+ + { "thread", bppy_get_thread, bppy_set_thread,
640
+ + "Thread ID for the breakpoint.\n\
641
+ +If the value is a thread ID (integer), then this is a thread-specific breakpoint.\n\
642
+ +If the value is None, then this breakpoint not thread-specific.\n\
643
+ +No other type of value can be used.", NULL },
644
+ + { "ignore_count", bppy_get_ignore_count, bppy_set_ignore_count,
645
+ + "Number of times this breakpoint should be automatically continued.",
646
+ + NULL },
647
+ + { "number", bppy_get_number, NULL,
648
+ + "Breakpoint's number assigned by GDB.", NULL },
649
+ + { "hit_count", bppy_get_hit_count, bppy_set_hit_count,
650
+ + "Number of times the breakpoint has been hit.\n\
651
+ +Can be set to zero to clear the count. No other value is valid\n\
652
+ +when setting this property.", NULL },
653
+ + { "location", bppy_get_location, NULL,
654
+ + "Location of the breakpoint, as specified by the user.", NULL},
655
+ +// { "condition", bppy_get_condition, bppy_set_condition,
656
+ +// "Condition of the breakpoint, as specified by the user, or None if no condition set."},
657
+ + { "commands", bppy_get_commands, NULL,
658
+ + "Commands of the breakpoint, as specified by the user."},
659
+ + { NULL } /* Sentinel. */
660
+ +};
661
+ +
662
+ +static PyMethodDef breakpoint_object_methods[] =
663
+ +{
664
+ + { "is_valid", bppy_is_valid, METH_NOARGS,
665
+ + "Return true if this breakpoint is valid, false if not." },
666
+ + { NULL } /* Sentinel. */
667
+ +};
668
+ +
669
+ +static PyTypeObject breakpoint_object_type =
670
+ +{
671
+ + PyObject_HEAD_INIT (NULL)
672
+ + 0, /*ob_size*/
673
+ + "gdb.Breakpoint", /*tp_name*/
674
+ + sizeof (breakpoint_object), /*tp_basicsize*/
675
+ + 0, /*tp_itemsize*/
676
+ + 0, /*tp_dealloc*/
677
+ + 0, /*tp_print*/
678
+ + 0, /*tp_getattr*/
679
+ + 0, /*tp_setattr*/
680
+ + 0, /*tp_compare*/
681
+ + 0, /*tp_repr*/
682
+ + 0, /*tp_as_number*/
683
+ + 0, /*tp_as_sequence*/
684
+ + 0, /*tp_as_mapping*/
685
+ + 0, /*tp_hash */
686
+ + 0, /*tp_call*/
687
+ + 0, /*tp_str*/
688
+ + 0, /*tp_getattro*/
689
+ + 0, /*tp_setattro*/
690
+ + 0, /*tp_as_buffer*/
691
+ + Py_TPFLAGS_DEFAULT, /*tp_flags*/
692
+ + "GDB breakpoint object", /* tp_doc */
693
+ + 0, /* tp_traverse */
694
+ + 0, /* tp_clear */
695
+ + 0, /* tp_richcompare */
696
+ + 0, /* tp_weaklistoffset */
697
+ + 0, /* tp_iter */
698
+ + 0, /* tp_iternext */
699
+ + breakpoint_object_methods, /* tp_methods */
700
+ + 0, /* tp_members */
701
+ + breakpoint_object_getset /* tp_getset */
702
+ +};
703
+ diff --git a/python/python-internal.h b/python/python-internal.h
704
+ index fbf8247..fa4a62b 100644
705
+ --- a/python/python-internal.h
706
+ +++ b/python/python-internal.h
707
+ @@ -69,6 +69,7 @@ extern PyTypeObject value_object_type;
708
+
709
+ PyObject *gdbpy_history (PyObject *self, PyObject *args);
710
+ PyObject *gdbpy_eval (PyObject *self, PyObject *args);
711
+ +PyObject *gdbpy_breakpoints (PyObject *, PyObject *);
712
+ PyObject *gdbpy_frame_stop_reason_string (PyObject *, PyObject *);
713
+ PyObject *gdbpy_selected_frame (PyObject *self, PyObject *args);
714
+ PyObject *gdbpy_lookup_type (PyObject *self, PyObject *args, PyObject *kw);
715
+ @@ -84,6 +85,7 @@ struct value *convert_value_from_python (PyObject *obj);
716
+ struct type *type_object_to_type (PyObject *obj);
717
+
718
+ void gdbpy_initialize_values (void);
719
+ +void gdbpy_initialize_breakpoints (void);
720
+ void gdbpy_initialize_frames (void);
721
+ void gdbpy_initialize_commands (void);
722
+ void gdbpy_initialize_types (void);
723
+ diff --git a/python/python.c b/python/python.c
724
+ index c96fa29..006ce29 100644
725
+ --- a/python/python.c
726
+ +++ b/python/python.c
727
+ @@ -594,6 +594,7 @@ Enables or disables auto-loading of Python code when an object is opened."),
728
+ PyModule_AddStringConstant (gdb_module, "TARGET_CONFIG", (char*) target_name);
729
+
730
+ gdbpy_initialize_values ();
731
+ + gdbpy_initialize_breakpoints ();
732
+ gdbpy_initialize_frames ();
733
+ gdbpy_initialize_commands ();
734
+ gdbpy_initialize_functions ();
735
+ @@ -658,6 +659,9 @@ static PyMethodDef GdbMethods[] =
736
+ { "parameter", gdbpy_parameter, METH_VARARGS,
737
+ "Return a gdb parameter's value" },
738
+
739
+ + { "breakpoints", gdbpy_breakpoints, METH_NOARGS,
740
+ + "Return a tuple of all breakpoint objects" },
741
+ +
742
+ { "default_visualizer", gdbpy_default_visualizer, METH_VARARGS,
743
+ "Find the default visualizer for a Value." },
744
+