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 +229 -0
- data/bin/gdb.rb +17 -0
- data/ext/Makefile +2 -0
- data/ext/extconf.rb +71 -0
- data/ext/src/gdb-7.0.tar.bz2 +0 -0
- data/gdb.rb.gemspec +32 -0
- data/patches/gdb-breakpoints.patch +744 -0
- data/patches/gdb-eval.patch +57 -0
- data/patches/gdb-leak.patch +183 -0
- data/scripts/ruby-gdb.py +404 -0
- metadata +64 -0
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
|
data/bin/gdb.rb
ADDED
@@ -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)
|
data/ext/Makefile
ADDED
data/ext/extconf.rb
ADDED
@@ -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
|
data/gdb.rb.gemspec
ADDED
@@ -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
|
+
|