1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/frame_host/debug_urls.h"
13 #include "base/command_line.h"
14 #include "base/debug/asan_invalid_access.h"
15 #include "base/debug/profiler.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/synchronization/waitable_event.h"
18 #include "base/threading/thread_restrictions.h"
19 #include "cc/base/switches.h"
20 #include "content/browser/gpu/gpu_process_host_ui_shim.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/common/content_constants.h"
23 #include "content/public/common/url_constants.h"
24 #include "ppapi/proxy/ppapi_messages.h"
27 #if defined(ENABLE_PLUGINS)
28 #include "content/browser/ppapi_plugin_process_host.h"
35 // Define the Asan debug URLs.
36 const char kAsanCrashDomain
[] = "crash";
37 const char kAsanHeapOverflow
[] = "/browser-heap-overflow";
38 const char kAsanHeapUnderflow
[] = "/browser-heap-underflow";
39 const char kAsanUseAfterFree
[] = "/browser-use-after-free";
41 const char kAsanCorruptHeapBlock
[] = "/browser-corrupt-heap-block";
42 const char kAsanCorruptHeap
[] = "/browser-corrupt-heap";
46 // Define the Kasko debug URLs.
47 const char kKaskoCrashDomain
[] = "kasko";
48 const char kKaskoSendReport
[] = "/send-report";
51 void HandlePpapiFlashDebugURL(const GURL
& url
) {
52 #if defined(ENABLE_PLUGINS)
53 bool crash
= url
== GURL(kChromeUIPpapiFlashCrashURL
);
55 std::vector
<PpapiPluginProcessHost
*> hosts
;
56 PpapiPluginProcessHost::FindByName(
57 base::UTF8ToUTF16(kFlashPluginName
), &hosts
);
58 for (std::vector
<PpapiPluginProcessHost
*>::iterator iter
= hosts
.begin();
59 iter
!= hosts
.end(); ++iter
) {
61 (*iter
)->Send(new PpapiMsg_Crash());
63 (*iter
)->Send(new PpapiMsg_Hang());
68 bool IsKaskoDebugURL(const GURL
& url
) {
70 return (url
.is_valid() && url
.SchemeIs(kChromeUIScheme
) &&
71 url
.DomainIs(kKaskoCrashDomain
) &&
72 url
.path() == kKaskoSendReport
);
78 void HandleKaskoDebugURL() {
80 // Signature of an enhanced crash reporting function.
81 typedef void(__cdecl
* ReportCrashWithProtobufPtr
)(EXCEPTION_POINTERS
*,
84 HMODULE exe_hmodule
= ::GetModuleHandle(NULL
);
85 ReportCrashWithProtobufPtr report_crash_with_protobuf
=
86 reinterpret_cast<ReportCrashWithProtobufPtr
>(
87 ::GetProcAddress(exe_hmodule
, "ReportCrashWithProtobuf"));
88 if (report_crash_with_protobuf
)
89 report_crash_with_protobuf(NULL
, "Invoked from debug url.");
97 bool IsAsanDebugURL(const GURL
& url
) {
99 if (!base::debug::IsBinaryInstrumented())
103 if (!(url
.is_valid() && url
.SchemeIs(kChromeUIScheme
) &&
104 url
.DomainIs(kAsanCrashDomain
) &&
109 if (url
.path() == kAsanHeapOverflow
|| url
.path() == kAsanHeapUnderflow
||
110 url
.path() == kAsanUseAfterFree
) {
114 #if defined(SYZYASAN)
115 if (url
.path() == kAsanCorruptHeapBlock
|| url
.path() == kAsanCorruptHeap
)
122 bool HandleAsanDebugURL(const GURL
& url
) {
123 #if defined(SYZYASAN)
124 if (!base::debug::IsBinaryInstrumented())
127 if (url
.path() == kAsanCorruptHeapBlock
) {
128 base::debug::AsanCorruptHeapBlock();
130 } else if (url
.path() == kAsanCorruptHeap
) {
131 base::debug::AsanCorruptHeap();
136 #if defined(ADDRESS_SANITIZER) || defined(SYZYASAN)
137 if (url
.path() == kAsanHeapOverflow
) {
138 base::debug::AsanHeapOverflow();
139 } else if (url
.path() == kAsanHeapUnderflow
) {
140 base::debug::AsanHeapUnderflow();
141 } else if (url
.path() == kAsanUseAfterFree
) {
142 base::debug::AsanHeapUseAfterFree();
154 class ScopedAllowWaitForDebugURL
{
156 base::ThreadRestrictions::ScopedAllowWait wait
;
159 bool HandleDebugURL(const GURL
& url
, ui::PageTransition transition
) {
160 // Ensure that the user explicitly navigated to this URL, unless
161 // kEnableGpuBenchmarking is enabled by Telemetry.
162 bool is_telemetry_navigation
=
163 base::CommandLine::ForCurrentProcess()->HasSwitch(
164 cc::switches::kEnableGpuBenchmarking
) &&
165 (transition
& ui::PAGE_TRANSITION_TYPED
);
167 if (!(transition
& ui::PAGE_TRANSITION_FROM_ADDRESS_BAR
) &&
168 !is_telemetry_navigation
)
171 if (IsAsanDebugURL(url
))
172 return HandleAsanDebugURL(url
);
174 if (IsKaskoDebugURL(url
)) {
175 HandleKaskoDebugURL();
179 if (url
== GURL(kChromeUIBrowserCrashURL
)) {
180 // Induce an intentional crash in the browser process.
185 if (url
== GURL(kChromeUIBrowserUIHang
)) {
186 ScopedAllowWaitForDebugURL allow_wait
;
187 base::WaitableEvent(false, false).Wait();
191 if (url
== GURL(kChromeUIGpuCleanURL
)) {
192 GpuProcessHostUIShim
* shim
= GpuProcessHostUIShim::GetOneInstance();
194 shim
->SimulateRemoveAllContext();
198 if (url
== GURL(kChromeUIGpuCrashURL
)) {
199 GpuProcessHostUIShim
* shim
= GpuProcessHostUIShim::GetOneInstance();
201 shim
->SimulateCrash();
205 if (url
== GURL(kChromeUIGpuHangURL
)) {
206 GpuProcessHostUIShim
* shim
= GpuProcessHostUIShim::GetOneInstance();
208 shim
->SimulateHang();
212 if (url
== GURL(kChromeUIPpapiFlashCrashURL
) ||
213 url
== GURL(kChromeUIPpapiFlashHangURL
)) {
214 BrowserThread::PostTask(BrowserThread::IO
, FROM_HERE
,
215 base::Bind(&HandlePpapiFlashDebugURL
, url
));
222 bool IsRendererDebugURL(const GURL
& url
) {
226 if (url
.SchemeIs(url::kJavaScriptScheme
))
229 return url
== GURL(kChromeUIBadCastCrashURL
) ||
230 url
== GURL(kChromeUICrashURL
) ||
231 url
== GURL(kChromeUIDumpURL
) ||
232 url
== GURL(kChromeUIKillURL
) ||
233 url
== GURL(kChromeUIHangURL
) ||
234 url
== GURL(kChromeUIShorthangURL
);
237 } // namespace content