passenger 5.0.30 → 5.1.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of passenger might be problematic. Click here for more details.

Files changed (131) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +30 -1
  3. data/CONTRIBUTING.md +1 -1
  4. data/CONTRIBUTORS +2 -0
  5. data/bin/passenger-install-nginx-module +18 -13
  6. data/build/agent.rb +1 -0
  7. data/build/basics.rb +1 -0
  8. data/build/cxx_tests.rb +6 -1
  9. data/build/misc.rb +3 -0
  10. data/build/packaging.rb +5 -17
  11. data/build/support/cxx_dependency_map.rb +100 -0
  12. data/build/support/vendor/cxxcodebuilder/lib/cxxcodebuilder/builder.rb +4 -1
  13. data/build/test_basics.rb +12 -2
  14. data/dev/ci/run_travis.sh +6 -2
  15. data/doc/Users guide Apache.html +7 -2
  16. data/doc/Users guide Apache.txt +4 -0
  17. data/resources/templates/error_layout.css +70 -84
  18. data/resources/templates/error_layout.html.template +84 -93
  19. data/resources/templates/standalone/http.erb +17 -13
  20. data/resources/templates/standalone/server.erb +2 -1
  21. data/resources/templates/undisclosed_error.html.template +52 -51
  22. data/resources/update_check_client_cert.p12 +0 -0
  23. data/resources/update_check_client_cert.pem +89 -0
  24. data/resources/update_check_server_pubkey.pem +14 -0
  25. data/src/agent/Core/ApplicationPool/ErrorRenderer.h +15 -1
  26. data/src/agent/Core/Controller.h +3 -2
  27. data/src/agent/Core/Controller/CheckoutSession.cpp +5 -4
  28. data/src/agent/Core/Controller/ForwardResponse.cpp +1 -1
  29. data/src/agent/Core/Controller/InitRequest.cpp +2 -0
  30. data/src/agent/Core/Controller/InitializationAndShutdown.cpp +1 -0
  31. data/src/agent/Core/Controller/Request.h +1 -0
  32. data/src/agent/Core/CoreMain.cpp +99 -2
  33. data/src/agent/Core/OptionParser.h +18 -1
  34. data/src/agent/Core/SecurityUpdateChecker.h +559 -0
  35. data/src/agent/Shared/Base.cpp +6 -1
  36. data/src/agent/TempDirToucher/TempDirToucherMain.cpp +52 -0
  37. data/src/agent/Watchdog/InstanceDirToucher.cpp +1 -2
  38. data/src/agent/Watchdog/WatchdogMain.cpp +31 -40
  39. data/src/apache2_module/Configuration.cpp +12 -0
  40. data/src/apache2_module/Configuration.hpp +5 -0
  41. data/src/apache2_module/ConfigurationCommands.cpp +19 -19
  42. data/src/apache2_module/ConfigurationCommands.cpp.cxxcodebuilder +2 -2
  43. data/src/apache2_module/ConfigurationFields.hpp +19 -19
  44. data/src/apache2_module/ConfigurationFields.hpp.cxxcodebuilder +2 -2
  45. data/src/apache2_module/ConfigurationSetters.cpp +19 -19
  46. data/src/apache2_module/ConfigurationSetters.cpp.cxxcodebuilder +2 -2
  47. data/src/apache2_module/CreateDirConfig.cpp +19 -19
  48. data/src/apache2_module/CreateDirConfig.cpp.cxxcodebuilder +2 -2
  49. data/src/apache2_module/Hooks.cpp +10 -1
  50. data/src/apache2_module/MergeDirConfig.cpp +19 -19
  51. data/src/apache2_module/MergeDirConfig.cpp.cxxcodebuilder +2 -2
  52. data/src/apache2_module/SetHeaders.cpp +19 -19
  53. data/src/apache2_module/SetHeaders.cpp.cxxcodebuilder +2 -2
  54. data/src/cxx_supportlib/Constants.h +22 -22
  55. data/src/cxx_supportlib/Constants.h.cxxcodebuilder +4 -1
  56. data/src/cxx_supportlib/Crypto.cpp +977 -0
  57. data/src/cxx_supportlib/Crypto.h +147 -0
  58. data/src/cxx_supportlib/InstanceDirectory.h +55 -2
  59. data/src/cxx_supportlib/Utils/Curl.h +24 -10
  60. data/src/cxx_supportlib/Utils/JsonUtils.h +1 -1
  61. data/src/cxx_supportlib/oxt/detail/spin_lock_darwin.hpp +2 -0
  62. data/src/cxx_supportlib/vendor-modified/boost/system/error_code.hpp +3 -3
  63. data/src/cxx_supportlib/vendor-modified/jsoncpp/json-forwards.h +167 -92
  64. data/src/cxx_supportlib/vendor-modified/jsoncpp/json.h +1827 -1542
  65. data/src/cxx_supportlib/vendor-modified/jsoncpp/jsoncpp.cpp +4705 -3652
  66. data/src/cxx_supportlib/vendor-modified/libev/Changes +46 -15
  67. data/src/cxx_supportlib/vendor-modified/libev/LICENSE +1 -1
  68. data/src/cxx_supportlib/vendor-modified/libev/Makefile.in +215 -128
  69. data/src/cxx_supportlib/vendor-modified/libev/aclocal.m4 +466 -275
  70. data/src/cxx_supportlib/vendor-modified/libev/config.guess +312 -418
  71. data/src/cxx_supportlib/vendor-modified/libev/config.sub +246 -105
  72. data/src/cxx_supportlib/vendor-modified/libev/configure +276 -72
  73. data/src/cxx_supportlib/vendor-modified/libev/configure.ac +2 -1
  74. data/src/cxx_supportlib/vendor-modified/libev/depcomp +346 -185
  75. data/src/cxx_supportlib/vendor-modified/libev/ev++.h +1 -1
  76. data/src/cxx_supportlib/vendor-modified/libev/ev.c +530 -190
  77. data/src/cxx_supportlib/vendor-modified/libev/ev.h +23 -14
  78. data/src/cxx_supportlib/vendor-modified/libev/ev_epoll.c +12 -6
  79. data/src/cxx_supportlib/vendor-modified/libev/ev_kqueue.c +9 -5
  80. data/src/cxx_supportlib/vendor-modified/libev/ev_poll.c +6 -3
  81. data/src/cxx_supportlib/vendor-modified/libev/ev_port.c +8 -4
  82. data/src/cxx_supportlib/vendor-modified/libev/ev_select.c +4 -2
  83. data/src/cxx_supportlib/vendor-modified/libev/ev_vars.h +3 -2
  84. data/src/cxx_supportlib/vendor-modified/libev/ev_win32.c +3 -4
  85. data/src/cxx_supportlib/vendor-modified/libev/install-sh +433 -219
  86. data/src/cxx_supportlib/vendor-modified/libev/libev.m4 +6 -6
  87. data/src/cxx_supportlib/vendor-modified/libev/ltmain.sh +2 -2
  88. data/src/cxx_supportlib/vendor-modified/libev/missing +167 -288
  89. data/src/cxx_supportlib/vendor-modified/libev/mkinstalldirs +72 -21
  90. data/src/cxx_supportlib/vendor-modified/modp_b64.cpp +4 -106
  91. data/src/cxx_supportlib/vendor-modified/modp_b64_data.h +37 -1
  92. data/src/cxx_supportlib/vendor-modified/modp_b64_strict_aliasing.cpp +119 -0
  93. data/src/helper-scripts/node-loader.js +72 -1
  94. data/src/nginx_module/CacheLocationConfig.c +52 -19
  95. data/src/nginx_module/CacheLocationConfig.c.cxxcodebuilder +2 -2
  96. data/src/nginx_module/Configuration.c +26 -1
  97. data/src/nginx_module/Configuration.h +2 -0
  98. data/src/nginx_module/ConfigurationCommands.c +35 -19
  99. data/src/nginx_module/ConfigurationCommands.c.cxxcodebuilder +2 -2
  100. data/src/nginx_module/ContentHandler.c +1 -1
  101. data/src/nginx_module/CreateLocationConfig.c +22 -19
  102. data/src/nginx_module/CreateLocationConfig.c.cxxcodebuilder +2 -2
  103. data/src/nginx_module/LocationConfig.h +21 -19
  104. data/src/nginx_module/LocationConfig.h.cxxcodebuilder +2 -2
  105. data/src/nginx_module/MergeLocationConfig.c +25 -19
  106. data/src/nginx_module/MergeLocationConfig.c.cxxcodebuilder +2 -2
  107. data/src/nginx_module/ngx_http_passenger_module.c +8 -4
  108. data/src/ruby_supportlib/phusion_passenger.rb +9 -4
  109. data/src/ruby_supportlib/phusion_passenger/admin_tools/instance.rb +2 -2
  110. data/src/ruby_supportlib/phusion_passenger/admin_tools/instance_registry.rb +1 -1
  111. data/src/ruby_supportlib/phusion_passenger/common_library.rb +13 -0
  112. data/src/ruby_supportlib/phusion_passenger/config/nginx_engine_compiler.rb +5 -2
  113. data/src/ruby_supportlib/phusion_passenger/constants.rb +1 -1
  114. data/src/ruby_supportlib/phusion_passenger/nginx/config_options.rb +15 -3
  115. data/src/ruby_supportlib/phusion_passenger/platform_info/crypto.rb +51 -0
  116. data/src/ruby_supportlib/phusion_passenger/platform_info/depcheck_specs/apache2.rb +7 -0
  117. data/src/ruby_supportlib/phusion_passenger/standalone/config_options_list.rb +17 -0
  118. data/src/ruby_supportlib/phusion_passenger/standalone/start_command.rb +4 -2
  119. data/src/ruby_supportlib/phusion_passenger/standalone/start_command/builtin_engine.rb +4 -0
  120. data/src/ruby_supportlib/phusion_passenger/standalone/start_command/nginx_engine.rb +5 -0
  121. data/src/ruby_supportlib/phusion_passenger/vendor/crash_watch/app.rb +19 -10
  122. data/src/ruby_supportlib/phusion_passenger/vendor/crash_watch/base.rb +25 -0
  123. data/src/ruby_supportlib/phusion_passenger/vendor/crash_watch/gdb_controller.rb +38 -103
  124. data/src/ruby_supportlib/phusion_passenger/vendor/crash_watch/lldb_controller.rb +178 -0
  125. data/src/ruby_supportlib/phusion_passenger/vendor/crash_watch/utils.rb +94 -0
  126. data/src/ruby_supportlib/phusion_passenger/vendor/crash_watch/version.rb +2 -2
  127. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core.rb +2 -2
  128. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/lib/union_station_hooks_core/version_data.rb +2 -2
  129. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/ruby_versions.yml.travis +5 -3
  130. data/src/ruby_supportlib/phusion_passenger/vendor/union_station_hooks_core/ruby_versions.yml.travis-with-sudo +9 -7
  131. metadata +14 -4
@@ -1,6 +1,6 @@
1
1
  # encoding: binary
2
2
  #
3
- # Copyright (c) 2010-2015 Phusion
3
+ # Copyright (c) 2010-2016 Phusion Holding B.V.
4
4
  #
5
5
  # Permission is hereby granted, free of charge, to any person obtaining
6
6
  # a copy of this software and associated documentation files (the
@@ -23,6 +23,7 @@
23
23
 
24
24
  require 'optparse'
25
25
  PhusionPassenger.require_passenger_lib 'vendor/crash_watch/gdb_controller'
26
+ PhusionPassenger.require_passenger_lib 'vendor/crash_watch/lldb_controller'
26
27
  PhusionPassenger.require_passenger_lib 'vendor/crash_watch/version'
27
28
 
28
29
  module CrashWatch
@@ -68,7 +69,11 @@ module CrashWatch
68
69
  end
69
70
 
70
71
  begin
71
- gdb = CrashWatch::GdbController.new
72
+ if !CrashWatch::Utils.gdb_installed? && CrashWatch::Utils.lldb_installed?
73
+ gdb = CrashWatch::LldbController.new
74
+ else
75
+ gdb = CrashWatch::GdbController.new
76
+ end
72
77
  rescue CrashWatch::Error => e
73
78
  abort e.message
74
79
  end
@@ -101,14 +106,18 @@ module CrashWatch
101
106
  output.gsub!(/^ (Thread .*):$/, "########### \\1 ###########\n")
102
107
  puts output
103
108
  else
104
- puts "Monitoring PID #{argv[0]}..."
105
- exit_info = gdb.wait_until_exit
106
- puts "Process exited at #{Time.now}."
107
- puts "Exit code: #{exit_info.exit_code}" if exit_info.exit_code
108
- puts "Signal: #{exit_info.signal}" if exit_info.signaled?
109
- if exit_info.backtrace
110
- puts "Backtrace:"
111
- puts " " << exit_info.backtrace.gsub(/\n/, "\n ")
109
+ if gdb.respond_to?(:wait_until_exit)
110
+ puts "Monitoring PID #{argv[0]}..."
111
+ exit_info = gdb.wait_until_exit
112
+ puts "Process exited at #{Time.now}."
113
+ puts "Exit code: #{exit_info.exit_code}" if exit_info.exit_code
114
+ puts "Signal: #{exit_info.signal}" if exit_info.signaled?
115
+ if exit_info.backtrace
116
+ puts "Backtrace:"
117
+ puts " " << exit_info.backtrace.gsub(/\n/, "\n ")
118
+ end
119
+ else
120
+ abort "ERROR: monitoring not supported with LLDB"
112
121
  end
113
122
  end
114
123
  else
@@ -0,0 +1,25 @@
1
+ # Copyright (c) 2016 Phusion Holding B.V.
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ module CrashWatch
23
+ class Error < StandardError
24
+ end
25
+ end
@@ -1,6 +1,6 @@
1
1
  # encoding: binary
2
2
  #
3
- # Copyright (c) 2010-2015 Phusion
3
+ # Copyright (c) 2010-2016 Phusion Holding B.V.
4
4
  #
5
5
  # Permission is hereby granted, free of charge, to any person obtaining
6
6
  # a copy of this software and associated documentation files (the
@@ -22,11 +22,10 @@
22
22
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
23
 
24
24
  require 'rbconfig'
25
+ PhusionPassenger.require_passenger_lib 'vendor/crash_watch/base'
26
+ PhusionPassenger.require_passenger_lib 'vendor/crash_watch/utils'
25
27
 
26
28
  module CrashWatch
27
- class Error < StandardError
28
- end
29
-
30
29
  class GdbNotFound < Error
31
30
  end
32
31
 
@@ -36,28 +35,28 @@ module CrashWatch
36
35
  class GdbController
37
36
  class ExitInfo
38
37
  attr_reader :exit_code, :signal, :backtrace, :snapshot
39
-
38
+
40
39
  def initialize(exit_code, signal, backtrace, snapshot)
41
40
  @exit_code = exit_code
42
41
  @signal = signal
43
42
  @backtrace = backtrace
44
43
  @snapshot = snapshot
45
44
  end
46
-
45
+
47
46
  def signaled?
48
47
  !!@signal
49
48
  end
50
49
  end
51
-
50
+
52
51
  END_OF_RESPONSE_MARKER = '--------END_OF_RESPONSE--------'
53
-
52
+
54
53
  attr_accessor :debug
55
54
 
56
55
  def initialize
57
- @pid, @in, @out = popen_command(find_gdb, "-n", "-q")
56
+ @pid, @in, @out = Utils.popen_command(find_gdb, "-n", "-q")
58
57
  execute("set prompt ")
59
58
  end
60
-
59
+
61
60
  def execute(command_string, timeout = nil)
62
61
  raise "GDB session is already closed" if !@pid
63
62
  puts "gdb write #{command_string.inspect}" if @debug
@@ -86,11 +85,11 @@ module CrashWatch
86
85
  end
87
86
  result
88
87
  end
89
-
88
+
90
89
  def closed?
91
90
  !@pid
92
91
  end
93
-
92
+
94
93
  def close
95
94
  if !closed?
96
95
  begin
@@ -106,7 +105,7 @@ module CrashWatch
106
105
  end
107
106
  end
108
107
  end
109
-
108
+
110
109
  def close!
111
110
  if !closed?
112
111
  @in.close
@@ -116,86 +115,48 @@ module CrashWatch
116
115
  @pid = nil
117
116
  end
118
117
  end
119
-
118
+
120
119
  def attach(pid)
121
120
  pid = pid.to_s.strip
122
121
  raise ArgumentError if pid.empty?
123
122
  result = execute("attach #{pid}")
124
123
  result !~ /(No such process|Unable to access task|Operation not permitted)/
125
124
  end
126
-
127
- def call(code)
128
- result = execute("call #{code}")
129
- result =~ /= (.*)$/
130
- $1
131
- end
132
-
125
+
133
126
  def program_counter
134
127
  execute("p/x $pc").gsub(/.* = /, '')
135
128
  end
136
-
129
+
137
130
  def current_thread
138
131
  execute("thread") =~ /Current thread is (.+?) /
139
132
  $1
140
133
  end
141
-
134
+
142
135
  def current_thread_backtrace
143
136
  execute("bt full").strip
144
137
  end
145
-
138
+
146
139
  def all_threads_backtraces
147
140
  execute("thread apply all bt full").strip
148
141
  end
149
-
150
- def ruby_backtrace
151
- filename = "/tmp/gdb-capture.#{@pid}.txt"
152
-
153
- orig_stdout_fd_copy = call("(int) dup(1)")
154
- new_stdout = call(%Q{(void *) fopen("#{filename}", "w")})
155
- new_stdout_fd = call("(int) fileno(#{new_stdout})")
156
- call("(int) dup2(#{new_stdout_fd}, 1)")
157
-
158
- # Let's hope stdout is set to line buffered or unbuffered mode...
159
- call("(void) rb_backtrace()")
160
-
161
- call("(int) dup2(#{orig_stdout_fd_copy}, 1)")
162
- call("(int) fclose(#{new_stdout})")
163
- call("(int) close(#{orig_stdout_fd_copy})")
164
-
165
- if File.exist?(filename)
166
- result = File.read(filename)
167
- result.strip!
168
- if result.empty?
169
- nil
170
- else
171
- result
172
- end
173
- else
174
- nil
175
- end
176
- ensure
177
- if filename
178
- File.unlink(filename) rescue nil
179
- end
180
- end
181
-
142
+
182
143
  def wait_until_exit
183
144
  execute("break _exit")
184
-
145
+
185
146
  signal = nil
186
147
  backtraces = nil
187
148
  snapshot = nil
188
-
149
+
189
150
  while true
190
151
  result = execute("continue")
191
- if result =~ /^Program received signal (.+?),/
192
- signal = $1
152
+ if result =~ /^(Program|Thread .*) received signal (.+?),/
153
+ signal = $2
193
154
  backtraces = execute("thread apply all bt full").strip
194
155
  if backtraces.empty?
195
156
  backtraces = execute("bt full").strip
196
157
  end
197
158
  snapshot = yield(self) if block_given?
198
-
159
+
199
160
  # This signal may or may not be immediately fatal; the
200
161
  # signal might be ignored by the process, or the process
201
162
  # has some clever signal handler that fixes the state,
@@ -204,12 +165,12 @@ module CrashWatch
204
165
  # the next machine instruction.
205
166
  old_program_counter = program_counter
206
167
  result = execute("stepi")
207
- if result =~ /^Program received signal .+?,/
168
+ if result =~ /^(Program|Thread .*) received signal .+?,/
208
169
  # Yes, it was fatal. Here we don't care whether the
209
170
  # instruction caused a different signal. The last
210
171
  # one is probably what we're interested in.
211
172
  return ExitInfo.new(nil, signal, backtraces, snapshot)
212
- elsif result =~ /^Program (terminated|exited)/ || result =~ /^Breakpoint .*? _exit/
173
+ elsif result =~ /^Program (terminated|exited)/ || result =~ /^Breakpoint .*? (__GI_)?_exit/
213
174
  # Running the next instruction causes the program to terminate.
214
175
  # Not sure what's going on but the previous signal and
215
176
  # backtrace is probably what we're interested in.
@@ -230,7 +191,8 @@ module CrashWatch
230
191
  else
231
192
  return ExitInfo.new(nil, signal, nil, snapshot)
232
193
  end
233
- elsif result =~ /^Breakpoint .*? _exit /
194
+ elsif result =~ /Breakpoint .*? (__GI_)?_exit (\(status=(\d+)\))?/
195
+ status_param = $3
234
196
  backtraces = execute("thread apply all bt full").strip
235
197
  if backtraces.empty?
236
198
  backtraces = execute("bt full").strip
@@ -240,53 +202,26 @@ module CrashWatch
240
202
  # even though the process exited. Kernel bug? In any case,
241
203
  # we put a timeout here so that we don't wait indefinitely.
242
204
  result = execute("continue", 10)
243
- if result =~ /^Program exited with code (\d+)\.$/
244
- return ExitInfo.new($1.to_i, nil, backtraces, snapshot)
245
- elsif result =~ /^Program exited normally/
205
+ if result =~ /^(Program|.*process .*) exited with code (\d+)/
206
+ return ExitInfo.new($2.to_i, nil, backtraces, snapshot)
207
+ elsif result =~ /^(Program|.*process .*) exited normally/
246
208
  return ExitInfo.new(0, nil, backtraces, snapshot)
247
- else
209
+ elsif status_param.nil? || status_param.empty?
248
210
  return ExitInfo.new(nil, nil, backtraces, snapshot)
211
+ else
212
+ return ExitInfo.new(status_param.to_i, nil, backtraces, snapshot)
249
213
  end
250
- elsif result =~ /^Program exited with code (\d+)\.$/
251
- return ExitInfo.new($1.to_i, nil, nil, nil)
252
- elsif result =~ /^Program exited normally/
214
+ elsif result =~ /^(Program|.*process .*) exited with code (\d+)\.$/
215
+ return ExitInfo.new($2.to_i, nil, nil, nil)
216
+ elsif result =~ /^(Program|.*process .*) exited normally/
253
217
  return ExitInfo.new(0, nil, nil, nil)
254
218
  else
255
219
  return ExitInfo.new(nil, nil, nil, nil)
256
220
  end
257
221
  end
258
222
  end
259
-
260
- private
261
- def popen_command(*command)
262
- a, b = IO.pipe
263
- c, d = IO.pipe
264
- if Process.respond_to?(:spawn)
265
- args = command.dup
266
- args << {
267
- STDIN => a,
268
- STDOUT => d,
269
- STDERR => d,
270
- :close_others => true
271
- }
272
- pid = Process.spawn(*args)
273
- else
274
- pid = fork do
275
- STDIN.reopen(a)
276
- STDOUT.reopen(d)
277
- STDERR.reopen(d)
278
- b.close
279
- c.close
280
- exec(*command)
281
- end
282
- end
283
- a.close
284
- d.close
285
- b.binmode
286
- c.binmode
287
- [pid, b, c]
288
- end
289
223
 
224
+ private
290
225
  def find_gdb
291
226
  result = nil
292
227
  if ENV['GDB'] && File.executable?(ENV['GDB'])
@@ -328,7 +263,7 @@ module CrashWatch
328
263
  end
329
264
  elsif result.nil?
330
265
  raise GdbNotFound,
331
- "*** ERROR ***: 'gdb' not found. Please install it (and if using Nginx " +
266
+ "*** ERROR ***: 'gdb' not found. Please install it (and if using Nginx " +
332
267
  "ensure that PATH isn't filtered out, see also its \"env\" option).\n" +
333
268
  " Debian/Ubuntu: sudo apt-get install gdb\n" +
334
269
  "RedHat/CentOS/Fedora: sudo yum install gdb\n" +
@@ -0,0 +1,178 @@
1
+ # encoding: binary
2
+ #
3
+ # Copyright (c) 2016 Phusion Holding B.V.
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining
6
+ # a copy of this software and associated documentation files (the
7
+ # "Software"), to deal in the Software without restriction, including
8
+ # without limitation the rights to use, copy, modify, merge, publish,
9
+ # distribute, sublicense, and/or sell copies of the Software, and to
10
+ # permit persons to whom the Software is furnished to do so, subject to
11
+ # the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be
14
+ # included in all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ require 'rbconfig'
25
+ PhusionPassenger.require_passenger_lib 'vendor/crash_watch/base'
26
+ PhusionPassenger.require_passenger_lib 'vendor/crash_watch/utils'
27
+
28
+ module CrashWatch
29
+ class LldbNotFound < Error
30
+ end
31
+
32
+ class LldbController
33
+ class ExitInfo
34
+ attr_reader :exit_code, :signal, :backtrace, :snapshot
35
+
36
+ def initialize(exit_code, signal, backtrace, snapshot)
37
+ @exit_code = exit_code
38
+ @signal = signal
39
+ @backtrace = backtrace
40
+ @snapshot = snapshot
41
+ end
42
+
43
+ def signaled?
44
+ !!@signal
45
+ end
46
+ end
47
+
48
+ END_OF_RESPONSE_MARKER = '--------END_OF_RESPONSE--------'
49
+
50
+ attr_accessor :debug
51
+
52
+ def initialize
53
+ @pid, @in, @out = Utils.popen_command(find_lldb, "-x")
54
+ execute("settings set prompt 'LLDB:'")
55
+ execute("settings set auto-confirm false")
56
+ end
57
+
58
+ def execute(command_string, timeout = nil)
59
+ raise "LLDB session is already closed" if !@pid
60
+ puts "lldb write #{command_string.inspect}" if @debug
61
+ marker = "\n#{END_OF_RESPONSE_MARKER}\n"
62
+ @in.puts(command_string)
63
+ @in.puts("script print #{marker.inspect}")
64
+ done = false
65
+ result = []
66
+ while !done
67
+ begin
68
+ if select([@out], nil, nil, timeout)
69
+ line = @out.readline.chomp
70
+ line.sub!(/^LLDB:/, '')
71
+ puts "lldb read #{line.inspect}" if @debug
72
+ if line == "#{END_OF_RESPONSE_MARKER}"
73
+ done = true
74
+ else
75
+ result << line
76
+ end
77
+ else
78
+ close!
79
+ done = true
80
+ result = nil
81
+ end
82
+ rescue EOFError
83
+ done = true
84
+ end
85
+ end
86
+
87
+ if result
88
+ # Remove echo of the command string
89
+ result.slice!(0, 2)
90
+ # Remove echo of the marker print command
91
+ result.pop
92
+ result.pop
93
+
94
+ result.join("\n") << "\n"
95
+ else
96
+ nil
97
+ end
98
+ end
99
+
100
+ def closed?
101
+ !@pid
102
+ end
103
+
104
+ def close
105
+ if !closed?
106
+ begin
107
+ execute("process detach", 5) if !closed?
108
+ execute("quit", 5) if !closed?
109
+ rescue Errno::EPIPE
110
+ end
111
+ if !closed?
112
+ @in.close
113
+ @out.close
114
+ Process.waitpid(@pid)
115
+ @pid = nil
116
+ end
117
+ end
118
+ end
119
+
120
+ def close!
121
+ if !closed?
122
+ @in.close
123
+ @out.close
124
+ Process.kill('KILL', @pid)
125
+ Process.waitpid(@pid)
126
+ @pid = nil
127
+ end
128
+ end
129
+
130
+ def attach(pid)
131
+ pid = pid.to_s.strip
132
+ raise ArgumentError if pid.empty?
133
+ result = execute("attach -p #{pid}")
134
+ result !~ /(unable to attach|cannot attach)/
135
+ end
136
+
137
+ def program_counter
138
+ execute("p/x $pc").gsub(/.* = /, '')
139
+ end
140
+
141
+ def current_thread
142
+ execute("thread info") =~ /^thread #(.+?): /
143
+ $1
144
+ end
145
+
146
+ def current_thread_backtrace
147
+ execute("bt").strip
148
+ end
149
+
150
+ def all_threads_backtraces
151
+ execute("bt all").strip
152
+ end
153
+
154
+ private
155
+ def find_lldb
156
+ result = nil
157
+ if ENV['LLDB'] && File.executable?(ENV['LLDB'])
158
+ result = ENV['LLDB']
159
+ else
160
+ ENV['PATH'].to_s.split(/:+/).each do |path|
161
+ filename = "#{path}/lldb"
162
+ if File.file?(filename) && File.executable?(filename)
163
+ result = filename
164
+ break
165
+ end
166
+ end
167
+ end
168
+
169
+ puts "Found lldb at: #{result}" if result
170
+
171
+ if result.nil?
172
+ raise LldbNotFound
173
+ else
174
+ result
175
+ end
176
+ end
177
+ end
178
+ end