gdb.rb 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+