Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(131)

Side by Side Diff: chrome/browser/nacl_host/nacl_process_host.cc

Issue 9950055: Enable --nacl-gdb flag on Linux. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/nacl_host/nacl_process_host.h" 5 #include "chrome/browser/nacl_host/nacl_process_host.h"
6 6
7 #include <string> 7 #include <string>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/command_line.h" 11 #include "base/command_line.h"
12 #include "base/memory/mru_cache.h" 12 #include "base/memory/mru_cache.h"
13 #include "base/memory/singleton.h" 13 #include "base/memory/singleton.h"
14 #include "base/message_loop.h"
14 #include "base/metrics/histogram.h" 15 #include "base/metrics/histogram.h"
15 #include "base/path_service.h" 16 #include "base/path_service.h"
17 #include "base/string_number_conversions.h"
18 #include "base/string_split.h"
16 #include "base/string_util.h" 19 #include "base/string_util.h"
17 #include "base/rand_util.h" 20 #include "base/rand_util.h"
18 #include "base/stringprintf.h" 21 #include "base/stringprintf.h"
19 #include "base/utf_string_conversions.h" 22 #include "base/utf_string_conversions.h"
20 #include "base/win/windows_version.h" 23 #include "base/win/windows_version.h"
21 #include "build/build_config.h" 24 #include "build/build_config.h"
22 #include "chrome/browser/extensions/extension_info_map.h" 25 #include "chrome/browser/extensions/extension_info_map.h"
23 #include "chrome/browser/renderer_host/chrome_render_message_filter.h" 26 #include "chrome/browser/renderer_host/chrome_render_message_filter.h"
24 #include "chrome/common/chrome_constants.h" 27 #include "chrome/common/chrome_constants.h"
25 #include "chrome/common/chrome_paths.h" 28 #include "chrome/common/chrome_paths.h"
(...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after
261 static bool RunningOnWOW64() { 264 static bool RunningOnWOW64() {
262 return (base::win::OSInfo::GetInstance()->wow64_status() == 265 return (base::win::OSInfo::GetInstance()->wow64_status() ==
263 base::win::OSInfo::WOW64_ENABLED); 266 base::win::OSInfo::WOW64_ENABLED);
264 } 267 }
265 #endif 268 #endif
266 269
267 NaClProcessHost::NaClProcessHost(const std::wstring& url) 270 NaClProcessHost::NaClProcessHost(const std::wstring& url)
268 : 271 :
269 #if defined(OS_WIN) 272 #if defined(OS_WIN)
270 process_launched_by_broker_(false), 273 process_launched_by_broker_(false),
274 #elif defined(OS_LINUX)
275 wait_for_nacl_gdb_(false),
271 #endif 276 #endif
272 reply_msg_(NULL), 277 reply_msg_(NULL),
273 internal_(new NaClInternal()), 278 internal_(new NaClInternal()),
274 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)), 279 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
275 enable_exception_handling_(false) { 280 enable_exception_handling_(false) {
276 process_.reset(content::BrowserChildProcessHost::Create( 281 process_.reset(content::BrowserChildProcessHost::Create(
277 content::PROCESS_TYPE_NACL_LOADER, this)); 282 content::PROCESS_TYPE_NACL_LOADER, this));
278 process_->SetName(WideToUTF16Hack(url)); 283 process_->SetName(WideToUTF16Hack(url));
279 284
280 // We allow untrusted hardware exception handling to be enabled via 285 // We allow untrusted hardware exception handling to be enabled via
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
401 internal_->sockets_for_sel_ldr.push_back(pair[1]); 406 internal_->sockets_for_sel_ldr.push_back(pair[1]);
402 SetCloseOnExec(pair[0]); 407 SetCloseOnExec(pair[0]);
403 SetCloseOnExec(pair[1]); 408 SetCloseOnExec(pair[1]);
404 } 409 }
405 410
406 // Launch the process 411 // Launch the process
407 if (!LaunchSelLdr()) { 412 if (!LaunchSelLdr()) {
408 delete this; 413 delete this;
409 } 414 }
410 } 415 }
411 416 #if defined(OS_WIN)
412 scoped_ptr<CommandLine> NaClProcessHost::LaunchWithNaClGdb( 417 scoped_ptr<CommandLine> NaClProcessHost::LaunchWithNaClGdb(
413 const FilePath& nacl_gdb, 418 const FilePath& nacl_gdb,
414 CommandLine* line, 419 CommandLine* line) {
415 const FilePath& manifest_path) {
416 CommandLine* cmd_line = new CommandLine(nacl_gdb); 420 CommandLine* cmd_line = new CommandLine(nacl_gdb);
417 // We can't use PrependWrapper because our parameters contain spaces. 421 // We can't use PrependWrapper because our parameters contain spaces.
418 cmd_line->AppendArg("--eval-command"); 422 cmd_line->AppendArg("--eval-command");
419 const FilePath::StringType& irt_path = 423 const FilePath::StringType& irt_path =
420 NaClBrowser::GetInstance()->GetIrtFilePath().value(); 424 NaClBrowser::GetInstance()->GetIrtFilePath().value();
421 cmd_line->AppendArgNative(FILE_PATH_LITERAL("nacl-irt ") + irt_path); 425 cmd_line->AppendArgNative(FILE_PATH_LITERAL("nacl-irt ") + irt_path);
426 FilePath manifest_path = GetManifestPath();
422 if (!manifest_path.empty()) { 427 if (!manifest_path.empty()) {
423 cmd_line->AppendArg("--eval-command"); 428 cmd_line->AppendArg("--eval-command");
424 cmd_line->AppendArgNative(FILE_PATH_LITERAL("nacl-manifest ") + 429 cmd_line->AppendArgNative(FILE_PATH_LITERAL("nacl-manifest ") +
425 manifest_path.value()); 430 manifest_path.value());
426 } 431 }
427 cmd_line->AppendArg("--args"); 432 cmd_line->AppendArg("--args");
428 const CommandLine::StringVector& argv = line->argv(); 433 const CommandLine::StringVector& argv = line->argv();
429 for (size_t i = 0; i < argv.size(); i++) { 434 for (size_t i = 0; i < argv.size(); i++) {
430 cmd_line->AppendArgNative(argv[i]); 435 cmd_line->AppendArgNative(argv[i]);
431 } 436 }
432 return scoped_ptr<CommandLine>(cmd_line); 437 return scoped_ptr<CommandLine>(cmd_line);
433 } 438 }
439 #elif defined(OS_LINUX)
440 namespace {
441 class NaClGdbWatchDelegate : public MessageLoopForIO::Watcher {
442 public:
443 // fd_write_ is used by nacl-gdb via /proc/browser_PID/fd/fd_write_
444 NaClGdbWatchDelegate(int fd_read, int fd_write,
445 const base::Closure& reply)
446 : fd_read_(fd_read),
447 fd_write_(fd_write),
448 reply_(reply) {}
449
450 ~NaClGdbWatchDelegate() {
451 if (HANDLE_EINTR(close(fd_read_)) != 0)
452 DLOG(ERROR) << "close(fd_read_) failed";
453 if (HANDLE_EINTR(close(fd_write_)) != 0)
454 DLOG(ERROR) << "close(fd_write_) failed";
455 }
456
457 virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE;
458 virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE {}
459
460 private:
461 int fd_read_;
462 int fd_write_;
463 base::Closure reply_;
464 };
465
466 void NaClGdbWatchDelegate::OnFileCanReadWithoutBlocking(int fd) {
467 char buf;
468 if (HANDLE_EINTR(read(fd_read_, &buf, 1)) != 1 || buf != '\0')
469 LOG(ERROR) << "Failed to sync with nacl-gdb";
470 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, reply_);
471 }
472 } // namespace
473
474 bool NaClProcessHost::LaunchNaClGdb(base::ProcessId pid) {
475 CommandLine::StringType nacl_gdb =
476 CommandLine::ForCurrentProcess()->GetSwitchValueNative(
477 switches::kNaClGdb);
478 CommandLine::StringVector argv;
479 // We don't support spaces inside arguments in --nacl-gdb switch.
480 base::SplitString(nacl_gdb, static_cast<CommandLine::CharType>(' '), &argv);
481 CommandLine cmd_line(argv);
482 cmd_line.AppendArg("--eval-command");
483 const FilePath::StringType& irt_path =
484 NaClBrowser::GetInstance()->GetIrtFilePath().value();
485 cmd_line.AppendArgNative(FILE_PATH_LITERAL("nacl-irt ") + irt_path);
486 FilePath manifest_path = GetManifestPath();
487 if (!manifest_path.empty()) {
488 cmd_line.AppendArg("--eval-command");
489 cmd_line.AppendArgNative(FILE_PATH_LITERAL("nacl-manifest ") +
490 manifest_path.value());
491 }
492 cmd_line.AppendArg("--eval-command");
493 cmd_line.AppendArg("attach " + base::IntToString(pid));
494 int fds[2];
495 if (pipe(fds) != 0)
496 return false;
497 // Tell the debugger to send a byte to the writable end of the pipe.
498 // We use a file descriptor in our process because the debugger will be
499 // typically launched in a separate terminal, and a lot of terminals close all
500 // file descriptors before launching external programs.
501 cmd_line.AppendArg("--eval-command");
502 cmd_line.AppendArg("dump binary value /proc/" +
503 base::IntToString(base::GetCurrentProcId()) +
504 "/fd/" + base::IntToString(fds[1]) + " (char)0");
505 // wait on fds[0]
506 // If the debugger crashes before attaching to the NaCl process, the user can
507 // release resources by terminating the NaCl loader in Chrome Task Manager.
508 nacl_gdb_watcher_delegate_.reset(
509 new NaClGdbWatchDelegate(
510 fds[0], fds[1],
511 base::Bind(&NaClProcessHost::OnNaClGdbAttached,
512 weak_factory_.GetWeakPtr())));
513 MessageLoopForIO::current()->WatchFileDescriptor(
514 fds[0],
515 true,
516 MessageLoopForIO::WATCH_READ,
517 &nacl_gdb_watcher_,
518 nacl_gdb_watcher_delegate_.get());
519 return base::LaunchProcess(cmd_line, base::LaunchOptions(), NULL);
520 }
521
522 void NaClProcessHost::OnNaClGdbAttached() {
523 wait_for_nacl_gdb_ = false;
524 nacl_gdb_watcher_.StopWatchingFileDescriptor();
525 nacl_gdb_watcher_delegate_.reset();
526 OnProcessLaunched();
527 }
528 #endif
529
530 FilePath NaClProcessHost::GetManifestPath() {
531 GURL manifest_url = GURL(process_->GetData().name);
532 const Extension* extension = extension_info_map_->extensions()
533 .GetExtensionOrAppByURL(ExtensionURLInfo(manifest_url));
534 if (extension != NULL && manifest_url.SchemeIs(chrome::kExtensionScheme)) {
535 std::string path = manifest_url.path();
536 TrimString(path, "/", &path); // Remove first slash
537 return extension->path().AppendASCII(path);
538 }
539 return FilePath();
540 }
434 541
435 bool NaClProcessHost::LaunchSelLdr() { 542 bool NaClProcessHost::LaunchSelLdr() {
436 std::string channel_id = process_->GetHost()->CreateChannel(); 543 std::string channel_id = process_->GetHost()->CreateChannel();
437 if (channel_id.empty()) 544 if (channel_id.empty())
438 return false; 545 return false;
439 546
440 CommandLine::StringType nacl_loader_prefix; 547 CommandLine::StringType nacl_loader_prefix;
441 #if defined(OS_POSIX) 548 #if defined(OS_POSIX)
442 nacl_loader_prefix = CommandLine::ForCurrentProcess()->GetSwitchValueNative( 549 nacl_loader_prefix = CommandLine::ForCurrentProcess()->GetSwitchValueNative(
443 switches::kNaClLoaderCmdPrefix); 550 switches::kNaClLoaderCmdPrefix);
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
482 cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id); 589 cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id);
483 if (logging::DialogsAreSuppressed()) 590 if (logging::DialogsAreSuppressed())
484 cmd_line->AppendSwitch(switches::kNoErrorDialogs); 591 cmd_line->AppendSwitch(switches::kNoErrorDialogs);
485 592
486 if (!nacl_loader_prefix.empty()) 593 if (!nacl_loader_prefix.empty())
487 cmd_line->PrependWrapper(nacl_loader_prefix); 594 cmd_line->PrependWrapper(nacl_loader_prefix);
488 595
489 FilePath nacl_gdb = CommandLine::ForCurrentProcess()->GetSwitchValuePath( 596 FilePath nacl_gdb = CommandLine::ForCurrentProcess()->GetSwitchValuePath(
490 switches::kNaClGdb); 597 switches::kNaClGdb);
491 if (!nacl_gdb.empty()) { 598 if (!nacl_gdb.empty()) {
492 GURL manifest_url = GURL(process_->GetData().name); 599 #if defined(OS_WIN)
493 FilePath manifest_path;
494 const Extension* extension = extension_info_map_->extensions().
495 GetExtensionOrAppByURL(ExtensionURLInfo(manifest_url));
496 if (extension != NULL && manifest_url.SchemeIs(chrome::kExtensionScheme)) {
497 std::string path = manifest_url.path();
498 TrimString(path, "/", &path); // Remove first slash
499 manifest_path = extension->path().AppendASCII(path);
500 }
501 cmd_line->AppendSwitch(switches::kNoSandbox); 600 cmd_line->AppendSwitch(switches::kNoSandbox);
502 scoped_ptr<CommandLine> gdb_cmd_line( 601 scoped_ptr<CommandLine> gdb_cmd_line(
503 LaunchWithNaClGdb(nacl_gdb, cmd_line.get(), manifest_path)); 602 LaunchWithNaClGdb(nacl_gdb, cmd_line.get()));
504 // We can't use process_->Launch() because OnProcessLaunched will be called 603 // We can't use process_->Launch() because OnProcessLaunched will be called
505 // with process_->GetData().handle filled by handle of gdb process. This 604 // with process_->GetData().handle filled by handle of gdb process. This
506 // handle will be used to duplicate handles for NaCl process and as 605 // handle will be used to duplicate handles for NaCl process and as
507 // a result NaCl process will not be able to use them. 606 // a result NaCl process will not be able to use them.
508 // 607 //
509 // So we don't fill process_->GetData().handle and wait for 608 // So we don't fill process_->GetData().handle and wait for
510 // OnChannelConnected to get handle of NaCl process from its pid. Then we 609 // OnChannelConnected to get handle of NaCl process from its pid. Then we
511 // call OnProcessLaunched. 610 // call OnProcessLaunched.
512 return base::LaunchProcess(*gdb_cmd_line, base::LaunchOptions(), NULL); 611 return base::LaunchProcess(*gdb_cmd_line, base::LaunchOptions(), NULL);
612 #elif defined(OS_LINUX)
613 wait_for_nacl_gdb_ = true;
614 #endif
513 } 615 }
514 616
515 // On Windows we might need to start the broker process to launch a new loader 617 // On Windows we might need to start the broker process to launch a new loader
516 #if defined(OS_WIN) 618 #if defined(OS_WIN)
517 if (RunningOnWOW64()) { 619 if (RunningOnWOW64()) {
518 return NaClBrokerService::GetInstance()->LaunchLoader(this, channel_id); 620 return NaClBrokerService::GetInstance()->LaunchLoader(this, channel_id);
519 } else { 621 } else {
520 process_->Launch(FilePath(), cmd_line.release()); 622 process_->Launch(FilePath(), cmd_line.release());
521 } 623 }
522 #elif defined(OS_POSIX) 624 #elif defined(OS_POSIX)
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
617 NULL, 719 NULL,
618 &error_code); 720 &error_code);
619 if (error_code != base::PLATFORM_FILE_OK) { 721 if (error_code != base::PLATFORM_FILE_OK) {
620 LOG(ERROR) << "Failed to open NaCl IRT file \"" 722 LOG(ERROR) << "Failed to open NaCl IRT file \""
621 << irt_filepath_.LossyDisplayName() 723 << irt_filepath_.LossyDisplayName()
622 << "\": " << error_code; 724 << "\": " << error_code;
623 } 725 }
624 } 726 }
625 727
626 void NaClProcessHost::OnProcessLaunched() { 728 void NaClProcessHost::OnProcessLaunched() {
729 #if defined(OS_LINUX)
730 if (wait_for_nacl_gdb_) {
731 if (LaunchNaClGdb(base::GetProcId(process_->GetData().handle))) {
732 // OnProcessLaunched will be called with wait_for_nacl_gdb_ = false once
733 // debugger is attached to the program.
734 return;
735 }
736 LOG(ERROR) << "Failed to launch debugger";
737 // Continue execution without debugger.
738 }
739 #endif
627 NaClBrowser* nacl_browser = NaClBrowser::GetInstance(); 740 NaClBrowser* nacl_browser = NaClBrowser::GetInstance();
628 741
629 if (nacl_browser->IrtAvailable()) { 742 if (nacl_browser->IrtAvailable()) {
630 // The IRT is already open. Away we go. 743 // The IRT is already open. Away we go.
631 SendStart(); 744 SendStart();
632 } else { 745 } else {
633 // We're waiting for the IRT to be open. 746 // We're waiting for the IRT to be open.
634 if (!nacl_browser->MakeIrtAvailable( 747 if (!nacl_browser->MakeIrtAvailable(
635 base::Bind(&NaClProcessHost::IrtReady, 748 base::Bind(&NaClProcessHost::IrtReady,
636 weak_factory_.GetWeakPtr()))) 749 weak_factory_.GetWeakPtr())))
(...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after
914 bool handled = true; 1027 bool handled = true;
915 IPC_BEGIN_MESSAGE_MAP(NaClProcessHost, msg) 1028 IPC_BEGIN_MESSAGE_MAP(NaClProcessHost, msg)
916 IPC_MESSAGE_HANDLER(NaClProcessMsg_QueryKnownToValidate, 1029 IPC_MESSAGE_HANDLER(NaClProcessMsg_QueryKnownToValidate,
917 OnQueryKnownToValidate) 1030 OnQueryKnownToValidate)
918 IPC_MESSAGE_HANDLER(NaClProcessMsg_SetKnownToValidate, 1031 IPC_MESSAGE_HANDLER(NaClProcessMsg_SetKnownToValidate,
919 OnSetKnownToValidate) 1032 OnSetKnownToValidate)
920 IPC_MESSAGE_UNHANDLED(handled = false) 1033 IPC_MESSAGE_UNHANDLED(handled = false)
921 IPC_END_MESSAGE_MAP() 1034 IPC_END_MESSAGE_MAP()
922 return handled; 1035 return handled;
923 } 1036 }
OLDNEW
« no previous file with comments | « chrome/browser/nacl_host/nacl_process_host.h ('k') | chrome/browser/nacl_host/test/mock_nacl_gdb.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698