<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/extensions_startup.h"

#include "base/string_util.h"
#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_switches.h"

#if defined(OS_WIN)
#include "ui/base/message_box_win.h"
#endif

ExtensionsStartupUtil::ExtensionsStartupUtil() : pack_job_succeeded_(false) {}

void ExtensionsStartupUtil::OnPackSuccess(
    const FilePath& crx_path,
    const FilePath& output_private_key_path) {
  pack_job_succeeded_ = true;
  ShowPackExtensionMessage(
      L"Extension Packaging Success",
      UTF16ToWideHack(PackExtensionJob::StandardSuccessMessage(
          crx_path, output_private_key_path)));
}

void ExtensionsStartupUtil::OnPackFailure(const std::string& error_message) {
  ShowPackExtensionMessage(L"Extension Packaging Error",
                           UTF8ToWide(error_message));
}

void ExtensionsStartupUtil::ShowPackExtensionMessage(
    const std::wstring& caption,
    const std::wstring& message) {
#if defined(OS_WIN)
  ui::MessageBox(NULL, message, caption, MB_OK | MB_SETFOREGROUND);
#else
  // Just send caption & text to stdout on mac & linux.
  std::string out_text = WideToASCII(caption);
  out_text.append("\n\n");
  out_text.append(WideToASCII(message));
  out_text.append("\n");
  base::StringPrintf("%s", out_text.c_str());
#endif
}

bool ExtensionsStartupUtil::PackExtension(const CommandLine& cmd_line) {
  if (!cmd_line.HasSwitch(switches::kPackExtension))
    return false;

  // Input Paths.
  FilePath src_dir = cmd_line.GetSwitchValuePath(switches::kPackExtension);
  FilePath private_key_path;
  if (cmd_line.HasSwitch(switches::kPackExtensionKey)) {
    private_key_path = cmd_line.GetSwitchValuePath(switches::kPackExtensionKey);
  }

  // Launch a job to perform the packing on the file thread.
  pack_job_ = new PackExtensionJob(this, src_dir, private_key_path);
  pack_job_->set_asynchronous(false);
  pack_job_->Start();

  return pack_job_succeeded_;
}

bool ExtensionsStartupUtil::UninstallExtension(const CommandLine& cmd_line,
                                               Profile* profile) {
  DCHECK(profile);

  if (!cmd_line.HasSwitch(switches::kUninstallExtension))
    return false;

  ExtensionService* extension_service = profile->GetExtensionService();
  if (!extension_service)
    return false;

  std::string extension_id = cmd_line.GetSwitchValueASCII(
      switches::kUninstallExtension);
  if (ExtensionService::UninstallExtensionHelper(extension_service,
                                                 extension_id)) {
    return true;
  }

  return false;
}

ExtensionsStartupUtil::~ExtensionsStartupUtil() {
  if (pack_job_.get())
    pack_job_->ClearClient();
}
<commit_msg>Packing extensions on the command line: actually send message to stdout.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/extensions_startup.h"

#include "base/string_util.h"
#include "base/stringprintf.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_switches.h"

#if defined(OS_WIN)
#include "ui/base/message_box_win.h"
#endif

ExtensionsStartupUtil::ExtensionsStartupUtil() : pack_job_succeeded_(false) {}

void ExtensionsStartupUtil::OnPackSuccess(
    const FilePath& crx_path,
    const FilePath& output_private_key_path) {
  pack_job_succeeded_ = true;
  ShowPackExtensionMessage(
      L"Extension Packaging Success",
      UTF16ToWideHack(PackExtensionJob::StandardSuccessMessage(
          crx_path, output_private_key_path)));
}

void ExtensionsStartupUtil::OnPackFailure(const std::string& error_message) {
  ShowPackExtensionMessage(L"Extension Packaging Error",
                           UTF8ToWide(error_message));
}

void ExtensionsStartupUtil::ShowPackExtensionMessage(
    const std::wstring& caption,
    const std::wstring& message) {
#if defined(OS_WIN)
  ui::MessageBox(NULL, message, caption, MB_OK | MB_SETFOREGROUND);
#else
  // Just send caption & text to stdout on mac & linux.
  std::string out_text = WideToASCII(caption);
  out_text.append("\n\n");
  out_text.append(WideToASCII(message));
  out_text.append("\n");
  printf("%s", out_text.c_str());
#endif
}

bool ExtensionsStartupUtil::PackExtension(const CommandLine& cmd_line) {
  if (!cmd_line.HasSwitch(switches::kPackExtension))
    return false;

  // Input Paths.
  FilePath src_dir = cmd_line.GetSwitchValuePath(switches::kPackExtension);
  FilePath private_key_path;
  if (cmd_line.HasSwitch(switches::kPackExtensionKey)) {
    private_key_path = cmd_line.GetSwitchValuePath(switches::kPackExtensionKey);
  }

  // Launch a job to perform the packing on the file thread.
  pack_job_ = new PackExtensionJob(this, src_dir, private_key_path);
  pack_job_->set_asynchronous(false);
  pack_job_->Start();

  return pack_job_succeeded_;
}

bool ExtensionsStartupUtil::UninstallExtension(const CommandLine& cmd_line,
                                               Profile* profile) {
  DCHECK(profile);

  if (!cmd_line.HasSwitch(switches::kUninstallExtension))
    return false;

  ExtensionService* extension_service = profile->GetExtensionService();
  if (!extension_service)
    return false;

  std::string extension_id = cmd_line.GetSwitchValueASCII(
      switches::kUninstallExtension);
  if (ExtensionService::UninstallExtensionHelper(extension_service,
                                                 extension_id)) {
    return true;
  }

  return false;
}

ExtensionsStartupUtil::~ExtensionsStartupUtil() {
  if (pack_job_.get())
    pack_job_->ClearClient();
}
<|endoftext|>


<commit_before><commit_msg>SWAPLONG->OSL_SWAPDWORD<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/user_script_master.h"

#include <string>
#include <vector>

#include "base/file_path.h"
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/pickle.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "base/thread.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/url_constants.h"
#include "net/base/net_util.h"

// Helper function to parse greasesmonkey headers
static bool GetDeclarationValue(const StringPiece& line,
                                const StringPiece& prefix,
                                std::string* value) {
  if (!line.starts_with(prefix))
    return false;

  std::string temp(line.data() + prefix.length(),
                   line.length() - prefix.length());
  TrimWhitespace(temp, TRIM_ALL, value);
  return true;
}

UserScriptMaster::ScriptReloader::ScriptReloader(UserScriptMaster* master)
    : master_(master),
      master_message_loop_(MessageLoop::current()) {
}

// static
bool UserScriptMaster::ScriptReloader::ParseMetadataHeader(
      const StringPiece& script_text, UserScript* script) {
  // http://wiki.greasespot.net/Metadata_block
  StringPiece line;
  size_t line_start = 0;
  size_t line_end = 0;
  bool in_metadata = false;

  static const StringPiece kUserScriptBegin("// ==UserScript==");
  static const StringPiece kUserScriptEng("// ==/UserScript==");
  static const StringPiece kIncludeDeclaration("// @include ");
  static const StringPiece kMatchDeclaration("// @match ");
  static const StringPiece kRunAtDeclaration("// @run-at ");
  static const StringPiece kRunAtDocumentStartValue("document-start");
  static const StringPiece kRunAtDocumentEndValue("document-end");

  while (line_start < script_text.length()) {
    line_end = script_text.find('\n', line_start);

    // Handle the case where there is no trailing newline in the file.
    if (line_end == std::string::npos) {
      line_end = script_text.length() - 1;
    }

    line.set(script_text.data() + line_start, line_end - line_start);

    if (!in_metadata) {
      if (line.starts_with(kUserScriptBegin)) {
        in_metadata = true;
      }
    } else {
      if (line.starts_with(kUserScriptEng)) {
        break;
      }

      std::string value;
      if (GetDeclarationValue(line, kIncludeDeclaration, &value)) {
        // We escape some characters that MatchPattern() considers special.
        ReplaceSubstringsAfterOffset(&value, 0, "\\", "\\\\");
        ReplaceSubstringsAfterOffset(&value, 0, "?", "\\?");
        script->add_glob(value);
      } else if (GetDeclarationValue(line, kMatchDeclaration, &value)) {
        URLPattern pattern;
        if (!pattern.Parse(value))
          return false;
        script->add_url_pattern(pattern);
      } else if (GetDeclarationValue(line, kRunAtDeclaration, &value)) {
        if (value == kRunAtDocumentStartValue)
          script->set_run_location(UserScript::DOCUMENT_START);
        else if (value != kRunAtDocumentEndValue)
          return false;
      }

      // TODO(aa): Handle more types of metadata.
    }

    line_start = line_end + 1;
  }

  // It is probably a mistake to declare both @include and @match rules.
  if (script->globs().size() > 0 && script->url_patterns().size() > 0)
    return false;

  // If no patterns were specified, default to @include *. This is what
  // Greasemonkey does.
  if (script->globs().size() == 0 && script->url_patterns().size() == 0)
    script->add_glob("*");

  return true;
}

void UserScriptMaster::ScriptReloader::StartScan(
    MessageLoop* work_loop, const FilePath& script_dir,
    const UserScriptList& lone_scripts) {
  // Add a reference to ourselves to keep ourselves alive while we're running.
  // Balanced by NotifyMaster().
  AddRef();
  work_loop->PostTask(FROM_HERE,
      NewRunnableMethod(this,
                        &UserScriptMaster::ScriptReloader::RunScan,
                        script_dir, lone_scripts));
}

void UserScriptMaster::ScriptReloader::NotifyMaster(
    base::SharedMemory* memory) {
  if (!master_) {
    // The master went away, so these new scripts aren't useful anymore.
    delete memory;
  } else {
    master_->NewScriptsAvailable(memory);
  }

  // Drop our self-reference.
  // Balances StartScan().
  Release();
}

static bool LoadScriptContent(UserScript::File* script_file) {
  std::string content;
  if (!file_util::ReadFileToString(script_file->path(), &content)) {
    LOG(WARNING) << "Failed to load user script file: "
                 << script_file->path().value();
    return false;
  }

  script_file->set_content(content);
  LOG(INFO) << "Loaded user script file: " << script_file->path().value();
  return true;
}

void UserScriptMaster::ScriptReloader::LoadScriptsFromDirectory(
    const FilePath& script_dir, UserScriptList* result) {
  // Clear the list. We will populate it with the scrips found in script_dir.
  result->clear();

  // Find all the scripts in |script_dir|.
  if (!script_dir.value().empty()) {
    // Create the "<Profile>/User Scripts" directory if it doesn't exist
    if (!file_util::DirectoryExists(script_dir))
      file_util::CreateDirectory(script_dir);

    file_util::FileEnumerator enumerator(script_dir, false,
                                         file_util::FileEnumerator::FILES,
                                         FILE_PATH_LITERAL("*.user.js"));
    for (FilePath file = enumerator.Next(); !file.value().empty();
         file = enumerator.Next()) {
      result->push_back(UserScript());
      UserScript& user_script = result->back();
      // Push single js file in this UserScript.
      GURL url(std::string(chrome::kUserScriptScheme) + ":/" +
          net::FilePathToFileURL(file).ExtractFileName());
      user_script.js_scripts().push_back(UserScript::File(file, url));
      UserScript::File& script_file = user_script.js_scripts().back();
      if (!LoadScriptContent(&script_file)) {
        result->erase(result->end());
      } else {
        ParseMetadataHeader(script_file.GetContent(), &user_script);
      }
    }
  }
}

static void LoadLoneScripts(UserScriptList* lone_scripts) {
  for (size_t i = 0; i < lone_scripts->size(); ++i) {
    UserScript& script = lone_scripts->at(i);
    for (size_t k = 0; k < script.js_scripts().size(); ++k) {
      UserScript::File& script_file = script.js_scripts()[k];
      if (script_file.GetContent().empty()) {
        LoadScriptContent(&script_file);
      }
    }
    for (size_t k = 0; k < script.css_scripts().size(); ++k) {
      UserScript::File& script_file = script.css_scripts()[k];
      if (script_file.GetContent().empty()) {
        LoadScriptContent(&script_file);
      }
    }
  }
}

// Pickle user scripts and return pointer to the shared memory.
static base::SharedMemory* Serialize(UserScriptList& scripts) {
  Pickle pickle;
  pickle.WriteSize(scripts.size());
  for (size_t i = 0; i < scripts.size(); i++) {
    UserScript& script = scripts[i];
    script.Pickle(&pickle);
    // Write scripts as 'data' so that we can read it out in the slave without
    // allocating a new string.
    for (size_t j = 0; j < script.js_scripts().size(); j++) {
      StringPiece contents = script.js_scripts()[j].GetContent();
      pickle.WriteData(contents.data(), contents.length());
    }
    for (size_t j = 0; j < script.css_scripts().size(); j++) {
      StringPiece contents = script.css_scripts()[j].GetContent();
      pickle.WriteData(contents.data(), contents.length());
    }
  }

  // Create the shared memory object.
  scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory());

  if (!shared_memory->Create(std::wstring(),  // anonymous
                             false,  // read-only
                             false,  // open existing
                             pickle.size())) {
    return NULL;
  }

  // Map into our process.
  if (!shared_memory->Map(pickle.size()))
    return NULL;

  // Copy the pickle to shared memory.
  memcpy(shared_memory->memory(), pickle.data(), pickle.size());

  return shared_memory.release();
}

// This method will be called from the file thread
void UserScriptMaster::ScriptReloader::RunScan(
    const FilePath script_dir, UserScriptList lone_script) {
  UserScriptList scripts;
  // Get list of user scripts.
  if (!script_dir.empty())
    LoadScriptsFromDirectory(script_dir, &scripts);

  LoadLoneScripts(&lone_script);

  // Merge with the explicit scripts
  scripts.reserve(scripts.size() + lone_script.size());
  scripts.insert(scripts.end(),
      lone_script.begin(), lone_script.end());

  // Scripts now contains list of up-to-date scripts. Load the content in the
  // shared memory and let the master know it's ready. We need to post the task
  // back even if no scripts ware found to balance the AddRef/Release calls
  master_message_loop_->PostTask(FROM_HERE,
      NewRunnableMethod(this,
                        &ScriptReloader::NotifyMaster,
                        Serialize(scripts)));
}

UserScriptMaster::UserScriptMaster(MessageLoop* worker_loop,
                                   const FilePath& script_dir)
    : user_script_dir_(script_dir),
      worker_loop_(worker_loop),
      extensions_service_ready_(false),
      pending_scan_(false) {
  if (!user_script_dir_.value().empty())
    AddWatchedPath(script_dir);

  registrar_.Add(this, NotificationType::EXTENSIONS_READY,
                 NotificationService::AllSources());
  registrar_.Add(this, NotificationType::EXTENSIONS_LOADED,
                 NotificationService::AllSources());
  registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
                 NotificationService::AllSources());
}

UserScriptMaster::~UserScriptMaster() {
  if (script_reloader_)
    script_reloader_->DisownMaster();

// TODO(aa): Enable this when DirectoryWatcher is implemented for linux.
#if defined(OS_WIN) || defined(OS_MACOSX)
  STLDeleteElements(&dir_watchers_);
#endif
}

void UserScriptMaster::AddWatchedPath(const FilePath& path) {
// TODO(aa): Enable this when DirectoryWatcher is implemented for linux.
#if defined(OS_WIN) || defined(OS_MACOSX)
  DirectoryWatcher* watcher = new DirectoryWatcher();
  base::Thread* file_thread = g_browser_process->file_thread();
  watcher->Watch(path, this, file_thread ? file_thread->message_loop() : NULL,
                 true);
  dir_watchers_.push_back(watcher);
#endif
}

void UserScriptMaster::NewScriptsAvailable(base::SharedMemory* handle) {
  // Ensure handle is deleted or released.
  scoped_ptr<base::SharedMemory> handle_deleter(handle);

  if (pending_scan_) {
    // While we were scanning, there were further changes.  Don't bother
    // notifying about these scripts and instead just immediately rescan.
    pending_scan_ = false;
    StartScan();
  } else {
    // We're no longer scanning.
    script_reloader_ = NULL;
    // We've got scripts ready to go.
    shared_memory_.swap(handle_deleter);

    NotificationService::current()->Notify(
        NotificationType::USER_SCRIPTS_UPDATED,
        NotificationService::AllSources(),
        Details<base::SharedMemory>(handle));
  }
}

void UserScriptMaster::OnDirectoryChanged(const FilePath& path) {
  if (script_reloader_.get()) {
    // We're already scanning for scripts.  We note that we should rescan when
    // we get the chance.
    pending_scan_ = true;
    return;
  }

  StartScan();
}

void UserScriptMaster::Observe(NotificationType type,
                               const NotificationSource& source,
                               const NotificationDetails& details) {
  switch (type.value) {
    case NotificationType::EXTENSIONS_READY:
      extensions_service_ready_ = true;
      StartScan();
      break;
    case NotificationType::EXTENSIONS_LOADED: {
      // TODO(aa): Fix race here. A page could need a content script on startup,
      // before the extension has loaded.  We need to freeze the renderer in
      // that case.
      // See: http://code.google.com/p/chromium/issues/detail?id=11547.

      // Add any content scripts inside the extension.
      ExtensionList* extensions = Details<ExtensionList>(details).ptr();
      for (ExtensionList::iterator extension_iterator = extensions->begin();
           extension_iterator != extensions->end(); ++extension_iterator) {
        Extension* extension = *extension_iterator;
        const UserScriptList& scripts = extension->content_scripts();
        for (UserScriptList::const_iterator iter = scripts.begin();
             iter != scripts.end(); ++iter) {
          lone_scripts_.push_back(*iter);
        }
      }
      if (extensions_service_ready_)
        StartScan();
      break;
    }

    case NotificationType::EXTENSION_UNLOADED: {
      // Remove any content scripts.
      Extension* extension = Details<Extension>(details).ptr();
      UserScriptList new_lone_scripts;
      for (UserScriptList::iterator iter = lone_scripts_.begin();
           iter != lone_scripts_.end(); ++iter) {
        if (iter->extension_id() != extension->id()) {
          new_lone_scripts.push_back(*iter);
        }
      }
      lone_scripts_ = new_lone_scripts;
      StartScan();

      // TODO(aa): Do we want to do something smarter for the scripts that have
      // already been injected?

      break;
    }

    default:
      DCHECK(false);
  }
}

void UserScriptMaster::StartScan() {
  if (!script_reloader_)
    script_reloader_ = new ScriptReloader(this);

  script_reloader_->StartScan(worker_loop_, user_script_dir_, lone_scripts_);
}
<commit_msg>vector.end() is out of range, need to erase (end() - 1)<commit_after>// Copyright (c) 2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/user_script_master.h"

#include <string>
#include <vector>

#include "base/file_path.h"
#include "base/file_util.h"
#include "base/path_service.h"
#include "base/pickle.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "base/thread.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/extensions_service.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/url_constants.h"
#include "net/base/net_util.h"

// Helper function to parse greasesmonkey headers
static bool GetDeclarationValue(const StringPiece& line,
                                const StringPiece& prefix,
                                std::string* value) {
  if (!line.starts_with(prefix))
    return false;

  std::string temp(line.data() + prefix.length(),
                   line.length() - prefix.length());
  TrimWhitespace(temp, TRIM_ALL, value);
  return true;
}

UserScriptMaster::ScriptReloader::ScriptReloader(UserScriptMaster* master)
    : master_(master),
      master_message_loop_(MessageLoop::current()) {
}

// static
bool UserScriptMaster::ScriptReloader::ParseMetadataHeader(
      const StringPiece& script_text, UserScript* script) {
  // http://wiki.greasespot.net/Metadata_block
  StringPiece line;
  size_t line_start = 0;
  size_t line_end = 0;
  bool in_metadata = false;

  static const StringPiece kUserScriptBegin("// ==UserScript==");
  static const StringPiece kUserScriptEng("// ==/UserScript==");
  static const StringPiece kIncludeDeclaration("// @include ");
  static const StringPiece kMatchDeclaration("// @match ");
  static const StringPiece kRunAtDeclaration("// @run-at ");
  static const StringPiece kRunAtDocumentStartValue("document-start");
  static const StringPiece kRunAtDocumentEndValue("document-end");

  while (line_start < script_text.length()) {
    line_end = script_text.find('\n', line_start);

    // Handle the case where there is no trailing newline in the file.
    if (line_end == std::string::npos)
      line_end = script_text.length() - 1;

    line.set(script_text.data() + line_start, line_end - line_start);

    if (!in_metadata) {
      if (line.starts_with(kUserScriptBegin))
        in_metadata = true;
    } else {
      if (line.starts_with(kUserScriptEng))
        break;

      std::string value;
      if (GetDeclarationValue(line, kIncludeDeclaration, &value)) {
        // We escape some characters that MatchPattern() considers special.
        ReplaceSubstringsAfterOffset(&value, 0, "\\", "\\\\");
        ReplaceSubstringsAfterOffset(&value, 0, "?", "\\?");
        script->add_glob(value);
      } else if (GetDeclarationValue(line, kMatchDeclaration, &value)) {
        URLPattern pattern;
        if (!pattern.Parse(value))
          return false;
        script->add_url_pattern(pattern);
      } else if (GetDeclarationValue(line, kRunAtDeclaration, &value)) {
        if (value == kRunAtDocumentStartValue)
          script->set_run_location(UserScript::DOCUMENT_START);
        else if (value != kRunAtDocumentEndValue)
          return false;
      }

      // TODO(aa): Handle more types of metadata.
    }

    line_start = line_end + 1;
  }

  // It is probably a mistake to declare both @include and @match rules.
  if (script->globs().size() > 0 && script->url_patterns().size() > 0)
    return false;

  // If no patterns were specified, default to @include *. This is what
  // Greasemonkey does.
  if (script->globs().size() == 0 && script->url_patterns().size() == 0)
    script->add_glob("*");

  return true;
}

void UserScriptMaster::ScriptReloader::StartScan(
    MessageLoop* work_loop, const FilePath& script_dir,
    const UserScriptList& lone_scripts) {
  // Add a reference to ourselves to keep ourselves alive while we're running.
  // Balanced by NotifyMaster().
  AddRef();
  work_loop->PostTask(FROM_HERE,
      NewRunnableMethod(this,
                        &UserScriptMaster::ScriptReloader::RunScan,
                        script_dir, lone_scripts));
}

void UserScriptMaster::ScriptReloader::NotifyMaster(
    base::SharedMemory* memory) {
  // The master went away, so these new scripts aren't useful anymore.
  if (!master_)
    delete memory;
  else
    master_->NewScriptsAvailable(memory);

  // Drop our self-reference.
  // Balances StartScan().
  Release();
}

static bool LoadScriptContent(UserScript::File* script_file) {
  std::string content;
  if (!file_util::ReadFileToString(script_file->path(), &content)) {
    LOG(WARNING) << "Failed to load user script file: "
                 << script_file->path().value();
    return false;
  }

  script_file->set_content(content);
  LOG(INFO) << "Loaded user script file: " << script_file->path().value();
  return true;
}

void UserScriptMaster::ScriptReloader::LoadScriptsFromDirectory(
    const FilePath& script_dir, UserScriptList* result) {
  // Clear the list. We will populate it with the scrips found in script_dir.
  result->clear();

  // Find all the scripts in |script_dir|.
  if (!script_dir.value().empty()) {
    // Create the "<Profile>/User Scripts" directory if it doesn't exist
    if (!file_util::DirectoryExists(script_dir))
      file_util::CreateDirectory(script_dir);

    file_util::FileEnumerator enumerator(script_dir, false,
                                         file_util::FileEnumerator::FILES,
                                         FILE_PATH_LITERAL("*.user.js"));
    for (FilePath file = enumerator.Next(); !file.value().empty();
         file = enumerator.Next()) {
      result->push_back(UserScript());
      UserScript& user_script = result->back();
      // Push single js file in this UserScript.
      GURL url(std::string(chrome::kUserScriptScheme) + ":/" +
          net::FilePathToFileURL(file).ExtractFileName());
      user_script.js_scripts().push_back(UserScript::File(file, url));
      UserScript::File& script_file = user_script.js_scripts().back();
      if (!LoadScriptContent(&script_file))
        result->pop_back();
      else
        ParseMetadataHeader(script_file.GetContent(), &user_script);
    }
  }
}

static void LoadLoneScripts(UserScriptList* lone_scripts) {
  for (size_t i = 0; i < lone_scripts->size(); ++i) {
    UserScript& script = lone_scripts->at(i);
    for (size_t k = 0; k < script.js_scripts().size(); ++k) {
      UserScript::File& script_file = script.js_scripts()[k];
      if (script_file.GetContent().empty())
        LoadScriptContent(&script_file);
    }
    for (size_t k = 0; k < script.css_scripts().size(); ++k) {
      UserScript::File& script_file = script.css_scripts()[k];
      if (script_file.GetContent().empty())
        LoadScriptContent(&script_file);
    }
  }
}

// Pickle user scripts and return pointer to the shared memory.
static base::SharedMemory* Serialize(const UserScriptList& scripts) {
  Pickle pickle;
  pickle.WriteSize(scripts.size());
  for (size_t i = 0; i < scripts.size(); i++) {
    const UserScript& script = scripts[i];
    script.Pickle(&pickle);
    // Write scripts as 'data' so that we can read it out in the slave without
    // allocating a new string.
    for (size_t j = 0; j < script.js_scripts().size(); j++) {
      StringPiece contents = script.js_scripts()[j].GetContent();
      pickle.WriteData(contents.data(), contents.length());
    }
    for (size_t j = 0; j < script.css_scripts().size(); j++) {
      StringPiece contents = script.css_scripts()[j].GetContent();
      pickle.WriteData(contents.data(), contents.length());
    }
  }

  // Create the shared memory object.
  scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory());

  if (!shared_memory->Create(std::wstring(),  // anonymous
                             false,  // read-only
                             false,  // open existing
                             pickle.size()))
    return NULL;

  // Map into our process.
  if (!shared_memory->Map(pickle.size()))
    return NULL;

  // Copy the pickle to shared memory.
  memcpy(shared_memory->memory(), pickle.data(), pickle.size());

  return shared_memory.release();
}

// This method will be called from the file thread
void UserScriptMaster::ScriptReloader::RunScan(
    const FilePath script_dir, UserScriptList lone_script) {
  UserScriptList scripts;
  // Get list of user scripts.
  if (!script_dir.empty())
    LoadScriptsFromDirectory(script_dir, &scripts);

  LoadLoneScripts(&lone_script);

  // Merge with the explicit scripts
  scripts.reserve(scripts.size() + lone_script.size());
  scripts.insert(scripts.end(),
      lone_script.begin(), lone_script.end());

  // Scripts now contains list of up-to-date scripts. Load the content in the
  // shared memory and let the master know it's ready. We need to post the task
  // back even if no scripts ware found to balance the AddRef/Release calls
  master_message_loop_->PostTask(FROM_HERE,
      NewRunnableMethod(this,
                        &ScriptReloader::NotifyMaster,
                        Serialize(scripts)));
}

UserScriptMaster::UserScriptMaster(MessageLoop* worker_loop,
                                   const FilePath& script_dir)
    : user_script_dir_(script_dir),
      worker_loop_(worker_loop),
      extensions_service_ready_(false),
      pending_scan_(false) {
  if (!user_script_dir_.value().empty())
    AddWatchedPath(script_dir);

  registrar_.Add(this, NotificationType::EXTENSIONS_READY,
                 NotificationService::AllSources());
  registrar_.Add(this, NotificationType::EXTENSIONS_LOADED,
                 NotificationService::AllSources());
  registrar_.Add(this, NotificationType::EXTENSION_UNLOADED,
                 NotificationService::AllSources());
}

UserScriptMaster::~UserScriptMaster() {
  if (script_reloader_)
    script_reloader_->DisownMaster();

// TODO(aa): Enable this when DirectoryWatcher is implemented for linux.
#if defined(OS_WIN) || defined(OS_MACOSX)
  STLDeleteElements(&dir_watchers_);
#endif
}

void UserScriptMaster::AddWatchedPath(const FilePath& path) {
// TODO(aa): Enable this when DirectoryWatcher is implemented for linux.
#if defined(OS_WIN) || defined(OS_MACOSX)
  DirectoryWatcher* watcher = new DirectoryWatcher();
  base::Thread* file_thread = g_browser_process->file_thread();
  watcher->Watch(path, this, file_thread ? file_thread->message_loop() : NULL,
                 true);
  dir_watchers_.push_back(watcher);
#endif
}

void UserScriptMaster::NewScriptsAvailable(base::SharedMemory* handle) {
  // Ensure handle is deleted or released.
  scoped_ptr<base::SharedMemory> handle_deleter(handle);

  if (pending_scan_) {
    // While we were scanning, there were further changes.  Don't bother
    // notifying about these scripts and instead just immediately rescan.
    pending_scan_ = false;
    StartScan();
  } else {
    // We're no longer scanning.
    script_reloader_ = NULL;
    // We've got scripts ready to go.
    shared_memory_.swap(handle_deleter);

    NotificationService::current()->Notify(
        NotificationType::USER_SCRIPTS_UPDATED,
        NotificationService::AllSources(),
        Details<base::SharedMemory>(handle));
  }
}

void UserScriptMaster::OnDirectoryChanged(const FilePath& path) {
  if (script_reloader_.get()) {
    // We're already scanning for scripts.  We note that we should rescan when
    // we get the chance.
    pending_scan_ = true;
    return;
  }

  StartScan();
}

void UserScriptMaster::Observe(NotificationType type,
                               const NotificationSource& source,
                               const NotificationDetails& details) {
  switch (type.value) {
    case NotificationType::EXTENSIONS_READY:
      extensions_service_ready_ = true;
      StartScan();
      break;
    case NotificationType::EXTENSIONS_LOADED: {
      // TODO(aa): Fix race here. A page could need a content script on startup,
      // before the extension has loaded.  We need to freeze the renderer in
      // that case.
      // See: http://code.google.com/p/chromium/issues/detail?id=11547.

      // Add any content scripts inside the extension.
      ExtensionList* extensions = Details<ExtensionList>(details).ptr();
      for (ExtensionList::iterator extension_iterator = extensions->begin();
           extension_iterator != extensions->end(); ++extension_iterator) {
        Extension* extension = *extension_iterator;
        const UserScriptList& scripts = extension->content_scripts();
        for (UserScriptList::const_iterator iter = scripts.begin();
             iter != scripts.end(); ++iter) {
          lone_scripts_.push_back(*iter);
        }
      }
      if (extensions_service_ready_)
        StartScan();
      break;
    }

    case NotificationType::EXTENSION_UNLOADED: {
      // Remove any content scripts.
      Extension* extension = Details<Extension>(details).ptr();
      UserScriptList new_lone_scripts;
      for (UserScriptList::iterator iter = lone_scripts_.begin();
           iter != lone_scripts_.end(); ++iter) {
        if (iter->extension_id() != extension->id())
          new_lone_scripts.push_back(*iter);
      }
      lone_scripts_ = new_lone_scripts;
      StartScan();

      // TODO(aa): Do we want to do something smarter for the scripts that have
      // already been injected?

      break;
    }

    default:
      DCHECK(false);
  }
}

void UserScriptMaster::StartScan() {
  if (!script_reloader_)
    script_reloader_ = new ScriptReloader(this);

  script_reloader_->StartScan(worker_loop_, user_script_dir_, lone_scripts_);
}
<|endoftext|>


<commit_before>#include <assert.h>
#include <cstdio>

#ifndef HAVE_LLVM
#error "This code needs LLVM enabled"
#endif

#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/Support/SourceMgr.h>
#include <llvm/Support/raw_ostream.h>
#include <llvm/IRReader/IRReader.h>

#include <iostream>
#include <string>
#include <queue>
#include <set>

#include "../src/llvm/LLVMDependenceGraph.h"
#include "../src/analysis/DFS.h"

using namespace dg;
using llvm::errs;

static struct {
    bool printCFG;
    bool printRevCFG;
    bool printBB;
    bool printBBonly;
    bool printPostDom;
    bool printControlDep;
    bool printDataDep;
} OPTIONS;

std::queue<LLVMDependenceGraph *> toPrint;

static std::string& getValueName(const llvm::Value *val, std::string &str)
{
    llvm::raw_string_ostream s(str);

    str.clear();

    if (!val) {
        s << "[NULL]";
        return s.str();
    }

    if (llvm::isa<llvm::Function>(val))
        s << "ENTRY " << val->getName();
    else
        s << *val;

    return s.str();
}

static void dump_to_dot(LLVMNode *n, std::ostream& out)
{
    const llvm::Value *val;

    if (OPTIONS.printControlDep)
        for (auto I = n->control_begin(), E = n->control_end();
             I != E; ++I)
            out << "\tNODE" << n << " -> NODE" <<  *I << "[color=green]\n";

    if (OPTIONS.printDataDep)
        for (auto I = n->data_begin(), E = n->data_end();
             I != E; ++I)
            out << "\tNODE" << n << " -> NODE" <<  *I
                << " [color=red]\n";

    if (OPTIONS.printCFG && !OPTIONS.printBBonly) {
        if (n->hasSuccessor()) {
            LLVMNode *succ = n->getSuccessor();
            if (!succ)
                errs() << "n hasSuccessor NULL!\n";

            out << "\tNODE" << n << " -> NODE" << succ
                << " [style=dotted rank=source]\n";
        }
    }

    if (OPTIONS.printRevCFG && !OPTIONS.printBBonly) {
        if (n->hasPredcessor()) {
            out << "\tNODE" << n << " -> NODE" <<  n->getPredcessor()
                << " [style=dotted color=gray]\n";
        }
    }

    // print edges between blocks
    if (OPTIONS.printCFG || OPTIONS.printBB) {
        auto BB = n->getBasicBlock();
        if (BB && BB->getLastNode() == n) {
            for (auto pred : BB->successors()) {
                auto fn = pred->getFirstNode();
                out << "\tNODE" << n << " -> NODE" << fn
                    << " [color=black]\n";
            }
        }
    }

    /*
    if (OPTIONS.printRevCFG || OPTIONS.printBB) {
        auto BB = n->getBasicBlock();
        // if this is BB header, print the edges
        if (BB && BB->getFirstNode() == n) {
            auto fn = BB->getFirstNode();
            for (auto pred : BB->predcessors()) {
                auto ln = pred->getLastNode();
                out << "\tNODE" << fn << " -> NODE" << ln
                    << " [style=dotted color=purple]\n";
            }
        }
    }
    */

    if (OPTIONS.printPostDom) {
        auto BB = n->getBasicBlock();
        if (BB && BB->getFirstNode() == n
            && BB->getIPostDomBy()) {
            auto pdBB = BB->getIPostDomBy();
            if (pdBB) {
                out << "\tNODE" << pdBB->getLastNode()
                    << " -> NODE" << n
                    << " [style=dashed color=purple rank=source]\n";
            } else {
                errs() << "WARN: No post-dom by for basic block for "
                       << BB << "\n";
            }
        }
    }
}

static void print_to_dot(LLVMDependenceGraph *dg,
                         std::ostream& out = std::cout);

static void printNode(LLVMNode *n,
                      std::ostream& out = std::cout)
{
    std::string valName;
    LLVMBBlock *BB = n->getBasicBlock();
    const llvm::Value *val = n->getValue();
    bool isBBHead = BB && n == BB->getFirstNode();
    bool isBBTail = BB && n == BB->getLastNode();

    assert(n);

    for (auto sub : n->getSubgraphs())
        toPrint.push(sub);

    LLVMDependenceGraph *params = n->getParameters();
    if (params) {
        toPrint.push(params);
    }

    // do not print node if we'd like to print only bblocks
    if (!(isBBHead || isBBTail) && OPTIONS.printBBonly)
        return;

    getValueName(val, valName);
    out << "\tNODE" << n << " [";

    if (isBBHead) {
        out << "style=\"filled\" fillcolor=\"lightgray\"";
    }

    out << " label=\"" << valName;

    if (OPTIONS.printBB && BB) {
        auto fn = BB->getFirstNode();
        if (!fn) {
            errs() << "CRITICAL: No first value for "
                   << valName << "\n";
        } else {
            auto fval = fn->getValue();
            if (!fval) {
                errs() << "WARN: No value in first value for "
                       << valName << "\n";
            } else {
                getValueName(fval, valName);
                out << "\\nBB: " << valName;
                if (n == fn)
                    out << "\\nBB head (preds "
                        << BB->predcessorsNum() << ")";
                if (BB->getLastNode() == n)
                    out << "\\nBB tail (succs "
                        << BB->successorsNum() << ")";
            }
        }
    }

    /*
    for (auto d : n->getDefs()) {
        getValueName(d->getValue(), valName);
        out << "\\nDEF " << valName;
    }
    for (auto d : n->getPtrs()) {
        getValueName(d->getValue(), valName);
        out << "\\nPTR " << valName;
    }
    */

    out << "\"];\n";
}

struct data
{
    data(LLVMDependenceGraph *d, std::ostream& o = std::cout)
        : dg(d), out(o) {}

    LLVMDependenceGraph *dg;
    std::ostream& out;
};

static void printBB(LLVMBBlock *BB, struct data& data)
{
    assert(BB);
    LLVMDependenceGraph *dg = data.dg;
    std::ostream& out = data.out;

    LLVMNode *n = BB->getFirstNode();
    static unsigned int bbid = 0;

    if (!n) {
        std::string valName;
        getValueName(dg->getEntry()->getValue(), valName);

        errs() << "WARN no first value in a block for "
               << valName << "\n";
        return;
    }

    out << "subgraph cluster_bb_" << bbid++;
    out << "{\n";
    out << "\tstyle=dotted\n";
    out << "label=\"LLVMBBlock " << BB;

    if (BB == dg->getEntryBB())
        out << " |> ENTRY <|";
    if (BB == dg->getExitBB())
        out << " |> EXIT <|";

    if (OPTIONS.printPostDom) {
        out << "\\n";
        for (LLVMBBlock *b : BB->getPostdominates())
            out << "\\nPDOM " << b;
    }

    out << "\"\n";

    do {
        printNode(n, out);
        n = n->getSuccessor();
    } while (n);

    out << "}\n";
}

static void printNodesOnly(LLVMDependenceGraph *dg,
                           std::ostream& out)
{
    for (auto I = dg->begin(), E = dg->end(); I != E; ++I) {
        printNode(I->second, out);
    }
}

static void dg_print_edges(LLVMDependenceGraph *dg,
                           std::ostream& out)
{
    for (auto I = dg->begin(), E = dg->end(); I != E; ++I) {
        auto n = I->second;
        if (!n) {
                errs() << "WARN [" << dg
                       << "]: Node is NULL for value: "
                       << *I->first << "\n";

            continue;
        }

        dump_to_dot(I->second, out);
    }

    // if this is a params dg, print edge from callsite to
    // this dg
        // add control edge from call-site to the parameters subgraph
        //out << "\tNODE" << n << " -> NODE" <<  params->getEntry()
        //    << "[label=\"params\"]\n";
        //

    // if this is a function, print edges here from callsites
   //for (auto sub : n->getSubgraphs()) {
   //    out << "\tNODE" << n << " -> NODE" <<  sub->getEntry()
   //        << " [style=dashed label=\"call\"]\n";
   //}

}

static void print_to_dot(LLVMDependenceGraph *dg,
                         std::ostream& out)
{
    static unsigned subgraph_no = 0;
    const llvm::Value *val;
    std::string valName;

    if (!dg)
        return;

    out << "subgraph \"cluster_" << subgraph_no++;
    out << "\" {\n";

    getValueName(dg->getEntry()->getValue(), valName);
    out << "label=\"<" << valName << ">";
    out << "\\n Nodes: " << dg->size() << "\"";

    out << " style=\"solid\"";

    LLVMBBlock *entryBB = dg->getEntryBB();
    if (!entryBB) {
        errs() << "No entry block in graph for " << valName << "\n";
        errs() << "  ^^^ printing only nodes\n";

        printNodesOnly(dg, out);
        out << "}\n";
        return;
    }

    printNodesOnly(dg, out);

    data d(dg);
    analysis::BBlockDFS<LLVMNode *> dfs;

    // run dfs and print every basic block you find
    dfs(entryBB, printBB, d);

    // print edges in dg
    dg_print_edges(dg, out);

    out << "}\n";
}

int main(int argc, char *argv[])
{
    llvm::LLVMContext context;
    llvm::SMDiagnostic SMD;
    std::unique_ptr<llvm::Module> M;
    const char *module = NULL;

    // default
    OPTIONS.printControlDep = true;
    OPTIONS.printDataDep = true;
    OPTIONS.printCFG = true;

    // parse options
    for (int i = 1; i < argc; ++i) {
        if (strcmp(argv[i], "-no-control") == 0) {
            OPTIONS.printControlDep = false;
        } else if (strcmp(argv[i], "-no-data") == 0) {
            OPTIONS.printDataDep = false;
        } else if (strcmp(argv[i], "-bb") == 0) {
            OPTIONS.printBB = true;
        } else if (strcmp(argv[i], "-bbonly") == 0) {
            OPTIONS.printBB = true;
            OPTIONS.printBBonly = true;
            OPTIONS.printDataDep = false;
        } else if (strcmp(argv[i], "-cfg") == 0) {
            OPTIONS.printCFG = true;
        } else if (strcmp(argv[i], "-cfgall") == 0) {
            OPTIONS.printCFG = true;
            OPTIONS.printRevCFG = true;
        } else if (strcmp(argv[i], "-pd") == 0) {
            OPTIONS.printPostDom = true;
        } else {
            module = argv[i];
        }
    }

    if (!module) {
        errs() << "Usage: % IR_module [output_file]\n";
        return 1;
    }

    M = llvm::parseIRFile(module, SMD, context);
    if (!M) {
        SMD.print(argv[0], errs());
        return 1;
    }

    LLVMDependenceGraph d;
    d.build(&*M);
    d.computePDTree();

    std::ostream& out = std::cout;
    std::set<LLVMDependenceGraph *> printed;

    out << "digraph \"DependencyGraph\" {\n";

    // print main procedure
    toPrint.push(&d);

    // print subgraphs that should be printed
    while (!toPrint.empty()) {
        auto sg = toPrint.front();
        toPrint.pop();

        if (printed.insert(sg).second)
            print_to_dot(sg, out);
    }

    out << "}\n";

    return 0;
}
<commit_msg>llvm-dump: remove PDTree<commit_after>#include <assert.h>
#include <cstdio>

#ifndef HAVE_LLVM
#error "This code needs LLVM enabled"
#endif

#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/Support/SourceMgr.h>
#include <llvm/Support/raw_ostream.h>
#include <llvm/IRReader/IRReader.h>

#include <iostream>
#include <string>
#include <queue>
#include <set>

#include "../src/llvm/LLVMDependenceGraph.h"
#include "../src/analysis/DFS.h"

using namespace dg;
using llvm::errs;

static struct {
    bool printCFG;
    bool printRevCFG;
    bool printBB;
    bool printBBonly;
    bool printPostDom;
    bool printControlDep;
    bool printDataDep;
} OPTIONS;

std::queue<LLVMDependenceGraph *> toPrint;

static std::string& getValueName(const llvm::Value *val, std::string &str)
{
    llvm::raw_string_ostream s(str);

    str.clear();

    if (!val) {
        s << "[NULL]";
        return s.str();
    }

    if (llvm::isa<llvm::Function>(val))
        s << "ENTRY " << val->getName();
    else
        s << *val;

    return s.str();
}

static void dump_to_dot(LLVMNode *n, std::ostream& out)
{
    const llvm::Value *val;

    if (OPTIONS.printControlDep)
        for (auto I = n->control_begin(), E = n->control_end();
             I != E; ++I)
            out << "\tNODE" << n << " -> NODE" <<  *I << "[color=green]\n";

    if (OPTIONS.printDataDep)
        for (auto I = n->data_begin(), E = n->data_end();
             I != E; ++I)
            out << "\tNODE" << n << " -> NODE" <<  *I
                << " [color=red]\n";

    if (OPTIONS.printCFG && !OPTIONS.printBBonly) {
        if (n->hasSuccessor()) {
            LLVMNode *succ = n->getSuccessor();
            if (!succ)
                errs() << "n hasSuccessor NULL!\n";

            out << "\tNODE" << n << " -> NODE" << succ
                << " [style=dotted rank=source]\n";
        }
    }

    if (OPTIONS.printRevCFG && !OPTIONS.printBBonly) {
        if (n->hasPredcessor()) {
            out << "\tNODE" << n << " -> NODE" <<  n->getPredcessor()
                << " [style=dotted color=gray]\n";
        }
    }

    // print edges between blocks
    if (OPTIONS.printCFG || OPTIONS.printBB) {
        auto BB = n->getBasicBlock();
        if (BB && BB->getLastNode() == n) {
            for (auto pred : BB->successors()) {
                auto fn = pred->getFirstNode();
                out << "\tNODE" << n << " -> NODE" << fn
                    << " [color=black]\n";
            }
        }
    }

    /*
    if (OPTIONS.printRevCFG || OPTIONS.printBB) {
        auto BB = n->getBasicBlock();
        // if this is BB header, print the edges
        if (BB && BB->getFirstNode() == n) {
            auto fn = BB->getFirstNode();
            for (auto pred : BB->predcessors()) {
                auto ln = pred->getLastNode();
                out << "\tNODE" << fn << " -> NODE" << ln
                    << " [style=dotted color=purple]\n";
            }
        }
    }
    */

    if (OPTIONS.printPostDom) {
        auto BB = n->getBasicBlock();
        if (BB && BB->getFirstNode() == n
            && BB->getIPostDomBy()) {
            auto pdBB = BB->getIPostDomBy();
            if (pdBB) {
                out << "\tNODE" << pdBB->getLastNode()
                    << " -> NODE" << n
                    << " [style=dashed color=purple rank=source]\n";
            } else {
                errs() << "WARN: No post-dom by for basic block for "
                       << BB << "\n";
            }
        }
    }
}

static void print_to_dot(LLVMDependenceGraph *dg,
                         std::ostream& out = std::cout);

static void printNode(LLVMNode *n,
                      std::ostream& out = std::cout)
{
    std::string valName;
    LLVMBBlock *BB = n->getBasicBlock();
    const llvm::Value *val = n->getValue();
    bool isBBHead = BB && n == BB->getFirstNode();
    bool isBBTail = BB && n == BB->getLastNode();

    assert(n);

    for (auto sub : n->getSubgraphs())
        toPrint.push(sub);

    LLVMDependenceGraph *params = n->getParameters();
    if (params) {
        toPrint.push(params);
    }

    // do not print node if we'd like to print only bblocks
    if (!(isBBHead || isBBTail) && OPTIONS.printBBonly)
        return;

    getValueName(val, valName);
    out << "\tNODE" << n << " [";

    if (isBBHead) {
        out << "style=\"filled\" fillcolor=\"lightgray\"";
    }

    out << " label=\"" << valName;

    if (OPTIONS.printBB && BB) {
        auto fn = BB->getFirstNode();
        if (!fn) {
            errs() << "CRITICAL: No first value for "
                   << valName << "\n";
        } else {
            auto fval = fn->getValue();
            if (!fval) {
                errs() << "WARN: No value in first value for "
                       << valName << "\n";
            } else {
                getValueName(fval, valName);
                out << "\\nBB: " << valName;
                if (n == fn)
                    out << "\\nBB head (preds "
                        << BB->predcessorsNum() << ")";
                if (BB->getLastNode() == n)
                    out << "\\nBB tail (succs "
                        << BB->successorsNum() << ")";
            }
        }
    }

    /*
    for (auto d : n->getDefs()) {
        getValueName(d->getValue(), valName);
        out << "\\nDEF " << valName;
    }
    for (auto d : n->getPtrs()) {
        getValueName(d->getValue(), valName);
        out << "\\nPTR " << valName;
    }
    */

    out << "\"];\n";
}

struct data
{
    data(LLVMDependenceGraph *d, std::ostream& o = std::cout)
        : dg(d), out(o) {}

    LLVMDependenceGraph *dg;
    std::ostream& out;
};

static void printBB(LLVMBBlock *BB, struct data& data)
{
    assert(BB);
    LLVMDependenceGraph *dg = data.dg;
    std::ostream& out = data.out;

    LLVMNode *n = BB->getFirstNode();
    static unsigned int bbid = 0;

    if (!n) {
        std::string valName;
        getValueName(dg->getEntry()->getValue(), valName);

        errs() << "WARN no first value in a block for "
               << valName << "\n";
        return;
    }

    out << "subgraph cluster_bb_" << bbid++;
    out << "{\n";
    out << "\tstyle=dotted\n";
    out << "label=\"LLVMBBlock " << BB;

    if (BB == dg->getEntryBB())
        out << " |> ENTRY <|";
    if (BB == dg->getExitBB())
        out << " |> EXIT <|";

    if (OPTIONS.printPostDom) {
        out << "\\n";
        for (LLVMBBlock *b : BB->getPostdominates())
            out << "\\nPDOM " << b;
    }

    out << "\"\n";

    do {
        printNode(n, out);
        n = n->getSuccessor();
    } while (n);

    out << "}\n";
}

static void printNodesOnly(LLVMDependenceGraph *dg,
                           std::ostream& out)
{
    for (auto I = dg->begin(), E = dg->end(); I != E; ++I) {
        printNode(I->second, out);
    }
}

static void dg_print_edges(LLVMDependenceGraph *dg,
                           std::ostream& out)
{
    for (auto I = dg->begin(), E = dg->end(); I != E; ++I) {
        auto n = I->second;
        if (!n) {
                errs() << "WARN [" << dg
                       << "]: Node is NULL for value: "
                       << *I->first << "\n";

            continue;
        }

        dump_to_dot(I->second, out);
    }

    // if this is a params dg, print edge from callsite to
    // this dg
        // add control edge from call-site to the parameters subgraph
        //out << "\tNODE" << n << " -> NODE" <<  params->getEntry()
        //    << "[label=\"params\"]\n";
        //

    // if this is a function, print edges here from callsites
   //for (auto sub : n->getSubgraphs()) {
   //    out << "\tNODE" << n << " -> NODE" <<  sub->getEntry()
   //        << " [style=dashed label=\"call\"]\n";
   //}

}

static void print_to_dot(LLVMDependenceGraph *dg,
                         std::ostream& out)
{
    static unsigned subgraph_no = 0;
    const llvm::Value *val;
    std::string valName;

    if (!dg)
        return;

    out << "subgraph \"cluster_" << subgraph_no++;
    out << "\" {\n";

    getValueName(dg->getEntry()->getValue(), valName);
    out << "label=\"<" << valName << ">";
    out << "\\n Nodes: " << dg->size() << "\"";

    out << " style=\"solid\"";

    LLVMBBlock *entryBB = dg->getEntryBB();
    if (!entryBB) {
        errs() << "No entry block in graph for " << valName << "\n";
        errs() << "  ^^^ printing only nodes\n";

        printNodesOnly(dg, out);
        out << "}\n";
        return;
    }

    printNodesOnly(dg, out);

    data d(dg);
    analysis::BBlockDFS<LLVMNode *> dfs;

    // run dfs and print every basic block you find
    dfs(entryBB, printBB, d);

    // print edges in dg
    dg_print_edges(dg, out);

    out << "}\n";
}

int main(int argc, char *argv[])
{
    llvm::LLVMContext context;
    llvm::SMDiagnostic SMD;
    std::unique_ptr<llvm::Module> M;
    const char *module = NULL;

    // default
    OPTIONS.printControlDep = true;
    OPTIONS.printDataDep = true;
    OPTIONS.printCFG = true;

    // parse options
    for (int i = 1; i < argc; ++i) {
        if (strcmp(argv[i], "-no-control") == 0) {
            OPTIONS.printControlDep = false;
        } else if (strcmp(argv[i], "-no-data") == 0) {
            OPTIONS.printDataDep = false;
        } else if (strcmp(argv[i], "-bb") == 0) {
            OPTIONS.printBB = true;
        } else if (strcmp(argv[i], "-bbonly") == 0) {
            OPTIONS.printBB = true;
            OPTIONS.printBBonly = true;
            OPTIONS.printDataDep = false;
        } else if (strcmp(argv[i], "-cfg") == 0) {
            OPTIONS.printCFG = true;
        } else if (strcmp(argv[i], "-cfgall") == 0) {
            OPTIONS.printCFG = true;
            OPTIONS.printRevCFG = true;
        } else if (strcmp(argv[i], "-pd") == 0) {
            OPTIONS.printPostDom = true;
        } else {
            module = argv[i];
        }
    }

    if (!module) {
        errs() << "Usage: % IR_module [output_file]\n";
        return 1;
    }

    M = llvm::parseIRFile(module, SMD, context);
    if (!M) {
        SMD.print(argv[0], errs());
        return 1;
    }

    LLVMDependenceGraph d;
    d.build(&*M);

    std::ostream& out = std::cout;
    std::set<LLVMDependenceGraph *> printed;

    out << "digraph \"DependencyGraph\" {\n";

    // print main procedure
    toPrint.push(&d);

    // print subgraphs that should be printed
    while (!toPrint.empty()) {
        auto sg = toPrint.front();
        toPrint.pop();

        if (printed.insert(sg).second)
            print_to_dot(sg, out);
    }

    out << "}\n";

    return 0;
}
<|endoftext|>


<commit_before>// -*- c-basic-offset: 2; related-file-name: "" -*-
/*
 * @(#)$Id$
 *
 * Copyright (c) 2004 Intel Corporation. All rights reserved.
 *
 * This file is distributed under the terms in the attached INTEL-LICENSE file.
 * If you do not find these files, copies can be found by writing to:
 * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300,
 * Berkeley, CA, 94704.  Attention:  Intel License Inquiry.
 *
 * DESCRIPTION: A chord dataflow.
 *
 */

#if HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */
#include <async.h>
#include <arpc.h>
#include <iostream>
#include <stdlib.h>

#include "tuple.h"
#include "router.h"
#include "val_int32.h"
#include "val_uint32.h"
#include "val_str.h"
#include "val_id.h"

#include "ol_lexer.h"
#include "ol_context.h"
#include "routerConfigGenerator.h"
#include "udp.h"

extern int ol_parser_debug;

static const int SUCCESSORSIZE = 16;

void killJoin()
{
  exit(0);
}

str LOCAL("127.0.0.1:10000");
str REMOTE("Remote.com");
str FINGERIP("Finger.com");

struct SuccessorGenerator : public FunctorSource::Generator
{
  virtual ~SuccessorGenerator() {};
  TupleRef operator()() const {

    TupleRef tuple = Tuple::mk();
    tuple->append(Val_Str::mk("successor"));

    str myAddress = str(strbuf() << LOCAL);
    tuple->append(Val_Str::mk(myAddress));

    IDRef successor = ID::mk((uint32_t) rand());
    tuple->append(Val_ID::mk(successor));

    str succAddress = str(strbuf() << successor->toString() << "IP");
    tuple->append(Val_Str::mk(succAddress));
    tuple->freeze();
    return tuple;
  }
};

struct SuccessorGenerator successorGenerator;

void initializeBaseTables(ref< OL_Context> ctxt, ref< RouterConfigGenerator> routerConfigGenerator)
{
  // create another dataflow to send in the lookups via another udp

  TableRef fingerTable = routerConfigGenerator->getTableByName(LOCAL, "finger");
  OL_Context::TableInfo* fingerTableInfo = ctxt->getTableInfos()->find("finger")->second;

  IDRef me = ID::mk((uint32_t) 1);

  // Fill up the table with fingers
  for (int i = 0;
       i < fingerTableInfo->size;
       i++) {
    TupleRef tuple = Tuple::mk();
    tuple->append(Val_Str::mk("finger"));

    str myAddress = str(strbuf() << LOCAL);
    tuple->append(Val_Str::mk(myAddress));

    IDRef target = ID::mk((uint32_t) 0X200)->shift(10 * i)->add(me);
    //tuple->append(Val_ID::mk(target));

    tuple->append(Val_Int32::mk(i));

    IDRef best = ID::mk()->add(target)->add(ID::mk((uint32_t) i*10));
    tuple->append(Val_ID::mk(best));

    str address = str(strbuf() << FINGERIP << ":" << i);
    tuple->append(Val_Str::mk(address));
    tuple->freeze();
    fingerTable->insert(tuple);
    std::cout << tuple->toString() << "\n";
  }

  {
    TableRef nodeTable = routerConfigGenerator->getTableByName(LOCAL, "node");
    TupleRef tuple = Tuple::mk();
    tuple->append(Val_Str::mk("node"));

    str myAddress = str(strbuf() << LOCAL);
    tuple->append(Val_Str::mk(myAddress));
    tuple->append(Val_ID::mk(me));
    tuple->freeze();
    nodeTable->insert(tuple);
    std::cout << "Node: " << tuple->toString() << "\n";
  }

  {
    TableRef bestSuccessorTable = routerConfigGenerator->getTableByName(LOCAL, "bestSuccessor");
    TupleRef tuple = Tuple::mk();
    tuple->append(Val_Str::mk("bestSuccessor"));

    str myAddress = str(strbuf() << LOCAL);
    tuple->append(Val_Str::mk(myAddress));

    IDRef target = ID::mk((uint32_t) 0X200)->add(me);
    IDRef best = ID::mk()->add(target)->add(ID::mk((uint) 10));
    tuple->append(Val_ID::mk(best));

    str address = str(strbuf() << FINGERIP << ":" << 0);
    tuple->append(Val_Str::mk(address));
    tuple->freeze();

    bestSuccessorTable->insert(tuple);
    std::cout << "BestSuccessor: " << tuple->toString() << "\n";
  }
}

void sendSuccessorStream(ref< Udp> udp, ref< Router::Configuration > conf)
{
  // have something that populates the table of successors. For testing purposes
  SuccessorGenerator* successorGenerator = new SuccessorGenerator();
  ElementSpecRef sourceS =
    conf->addElement(New refcounted< FunctorSource >(str("SuccessorSource:"),
						     successorGenerator));

  ElementSpecRef print   = conf->addElement(New refcounted< Print >(strbuf("Successor")));

  // The timed pusher
  ElementSpecRef pushS =
    conf->addElement(New refcounted< TimedPullPush >(strbuf("SuccessorPush:"),
						     2));

  // And a slot from which to pull
  ElementSpecRef slotS =
    conf->addElement(New refcounted< Slot >(strbuf("SuccessorSlot:")));

  ElementSpecRef encap = conf->addElement(New refcounted< PelTransform >("Encap",
									 "$1 pop \
                                                     $0 ->t $1 append $2 append $3 append pop")); // the rest
  ElementSpecRef marshal = conf->addElement(New refcounted< MarshalField >("MarshalField", 1));
  ElementSpecRef route   = conf->addElement(New refcounted< StrToSockaddr >(strbuf("Route"), 0));

  ElementSpecRef udpTx = conf->addElement(udp->get_tx());

  conf->hookUp(sourceS, 0, print, 0);
  conf->hookUp(print, 0, pushS, 0);
  conf->hookUp(pushS, 0, slotS, 0);
  conf->hookUp(slotS, 0, encap, 0);
  conf->hookUp(encap, 0, marshal, 0);
  conf->hookUp(marshal, 0, route, 0);
  conf->hookUp(route, 0, udpTx, 0);

 }

/** Test lookups. */
void startChord(LoggerI::Level level, ref< OL_Context> ctxt, str datalogFile)
{
  // create dataflow for translated chord lookup rules
  Router::ConfigurationRef conf = New refcounted< Router::Configuration >();
  ref< RouterConfigGenerator > routerConfigGenerator = New refcounted< RouterConfigGenerator >(ctxt, conf, false, true, datalogFile);

  routerConfigGenerator->createTables(LOCAL);

  ref< Udp > udp = New refcounted< Udp > (LOCAL, 10000);
  ref< Udp > bootstrapUdp = New refcounted< Udp > ("Bootstrap", 9999);
  routerConfigGenerator->configureRouter(udp, LOCAL);

  // populate the finger entries
  initializeBaseTables(ctxt, routerConfigGenerator);
  sendSuccessorStream(bootstrapUdp, conf);

  RouterRef router = New refcounted< Router >(conf, level);
  if (router->initialize(router) == 0) {
    std::cout << "Correctly initialized network of chord lookup flows.\n";
  } else {
    std::cout << "** Failed to initialize correct spec\n";
    return;
  }

  // Activate the router
  router->activate();

  // Run the router
  amain();
}

int main(int argc, char **argv)
{
  std::cout << "\nTranslated Chord\n";

  if (argc < 2) {
    std::cerr << "Usage: ./chordDatalog file [loglevel seed]\n";
    return 1;
  }

  ref< OL_Context > ctxt = New refcounted< OL_Context>();
  strbuf filename;
  filename << argv[1];
  str file(filename);
  std::ifstream istr(file);
  ctxt->parse_stream(&istr);

  LoggerI::Level level = LoggerI::WARN;

  if (argc > 2) {
    str levelName(argv[2]);
    level = LoggerI::levelFromName[levelName];
  }

  int seed = 0;
  if (argc > 3) {
    seed = atoi(argv[3]);
  }
  srand(seed);

  startChord(level, ctxt, file);
  return 0;
}

<commit_msg>chordDatalog<commit_after>// -*- c-basic-offset: 2; related-file-name: "" -*-
/*
 * @(#)$Id$
 *
 * Copyright (c) 2004 Intel Corporation. All rights reserved.
 *
 * This file is distributed under the terms in the attached INTEL-LICENSE file.
 * If you do not find these files, copies can be found by writing to:
 * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300,
 * Berkeley, CA, 94704.  Attention:  Intel License Inquiry.
 *
 * DESCRIPTION: A chord dataflow.
 *
 */

#if HAVE_CONFIG_H
#include <config.h>
#endif /* HAVE_CONFIG_H */
#include <async.h>
#include <arpc.h>
#include <iostream>
#include <stdlib.h>

#include "tuple.h"
#include "router.h"
#include "val_int32.h"
#include "val_uint32.h"
#include "val_str.h"
#include "val_id.h"

#include "ol_lexer.h"
#include "ol_context.h"
#include "routerConfigGenerator.h"
#include "udp.h"

extern int ol_parser_debug;

static const int SUCCESSORSIZE = 16;

void killJoin()
{
  exit(0);
}

str LOCAL("127.0.0.1:10000");
str REMOTE("Remote.com");
str FINGERIP("Finger.com");

struct SuccessorGenerator : public FunctorSource::Generator
{
  virtual ~SuccessorGenerator() {};
  TupleRef operator()() const {

    TupleRef tuple = Tuple::mk();
    tuple->append(Val_Str::mk("successor"));

    str myAddress = str(strbuf() << LOCAL);
    tuple->append(Val_Str::mk(myAddress));

    IDRef successor = ID::mk((uint32_t) rand());
    tuple->append(Val_ID::mk(successor));

    str succAddress = str(strbuf() << successor->toString() << "IP");
    tuple->append(Val_Str::mk(succAddress));
    tuple->freeze();
    return tuple;
  }
};

struct SuccessorGenerator successorGenerator;

void initializeBaseTables(ref< OL_Context> ctxt, ref< RouterConfigGenerator> routerConfigGenerator)
{
  // create another dataflow to send in the lookups via another udp

  TableRef fingerTable = routerConfigGenerator->getTableByName(LOCAL, "finger");
  OL_Context::TableInfo* fingerTableInfo = ctxt->getTableInfos()->find("finger")->second;

  IDRef me = ID::mk((uint32_t) 1);

  // Fill up the table with fingers
  for (int i = 0;
       i < fingerTableInfo->size;
       i++) {
    TupleRef tuple = Tuple::mk();
    tuple->append(Val_Str::mk("finger"));

    str myAddress = str(strbuf() << LOCAL);
    tuple->append(Val_Str::mk(myAddress));

    IDRef target = ID::mk((uint32_t) 0X200)->shift(10 * i)->add(me);
    //tuple->append(Val_ID::mk(target));

    tuple->append(Val_Int32::mk(i));

    IDRef best = ID::mk()->add(target)->add(ID::mk((uint32_t) i*10));
    tuple->append(Val_ID::mk(best));

    str address = str(strbuf() << FINGERIP << ":" << i);
    tuple->append(Val_Str::mk(address));
    tuple->freeze();
    fingerTable->insert(tuple);
    std::cout << tuple->toString() << "\n";
  }

  {
    TableRef nodeTable = routerConfigGenerator->getTableByName(LOCAL, "node");
    TupleRef tuple = Tuple::mk();
    tuple->append(Val_Str::mk("node"));

    str myAddress = str(strbuf() << LOCAL);
    tuple->append(Val_Str::mk(myAddress));
    tuple->append(Val_ID::mk(me));
    tuple->freeze();
    nodeTable->insert(tuple);
    std::cout << "Node: " << tuple->toString() << "\n";
  }

  {
    TableRef bestSuccessorTable = routerConfigGenerator->getTableByName(LOCAL, "bestSuccessor");
    TupleRef tuple = Tuple::mk();
    tuple->append(Val_Str::mk("bestSuccessor"));

    str myAddress = str(strbuf() << LOCAL);
    tuple->append(Val_Str::mk(myAddress));

    IDRef target = ID::mk((uint32_t) 0X200)->add(me);
    IDRef best = ID::mk()->add(target)->add(ID::mk((uint) 10));
    tuple->append(Val_ID::mk(best));

    str address = str(strbuf() << FINGERIP << ":" << 0);
    tuple->append(Val_Str::mk(address));
    tuple->freeze();

    bestSuccessorTable->insert(tuple);
    std::cout << "BestSuccessor: " << tuple->toString() << "\n";
    }

  TableRef nextFingerFixTable = routerConfigGenerator->getTableByName(LOCAL, "nextFingerFix");
  TupleRef nextFingerFixTuple = Tuple::mk();
  nextFingerFixTuple->append(Val_Str::mk("nextFingerFix"));
  nextFingerFixTuple->append(Val_Str::mk(LOCAL));
  nextFingerFixTuple->append(Val_Int32::mk(0));
  nextFingerFixTuple->freeze();
  nextFingerFixTable->insert(nextFingerFixTuple);
  std::cout << "Next finger fix: " << nextFingerFixTuple->toString() << "\n";
}

void sendSuccessorStream(ref< Udp> udp, ref< Router::Configuration > conf)
{
  // have something that populates the table of successors. For testing purposes
  SuccessorGenerator* successorGenerator = new SuccessorGenerator();
  ElementSpecRef sourceS =
    conf->addElement(New refcounted< FunctorSource >(str("SuccessorSource:"),
						     successorGenerator));

  ElementSpecRef print   = conf->addElement(New refcounted< Print >(strbuf("Successor")));

  // The timed pusher
  ElementSpecRef pushS =
    conf->addElement(New refcounted< TimedPullPush >(strbuf("SuccessorPush:"),
						     2));

  // And a slot from which to pull
  ElementSpecRef slotS =
    conf->addElement(New refcounted< Slot >(strbuf("SuccessorSlot:")));

  ElementSpecRef encap = conf->addElement(New refcounted< PelTransform >("Encap",
									 "$1 pop \
                                                     $0 ->t $1 append $2 append $3 append pop")); // the rest
  ElementSpecRef marshal = conf->addElement(New refcounted< MarshalField >("MarshalField", 1));
  ElementSpecRef route   = conf->addElement(New refcounted< StrToSockaddr >(strbuf("Route"), 0));

  ElementSpecRef udpTx = conf->addElement(udp->get_tx());

  conf->hookUp(sourceS, 0, print, 0);
  conf->hookUp(print, 0, pushS, 0);
  conf->hookUp(pushS, 0, slotS, 0);
  conf->hookUp(slotS, 0, encap, 0);
  conf->hookUp(encap, 0, marshal, 0);
  conf->hookUp(marshal, 0, route, 0);
  conf->hookUp(route, 0, udpTx, 0);

 }

/** Test lookups. */
void startChord(LoggerI::Level level, ref< OL_Context> ctxt, str datalogFile)
{
  // create dataflow for translated chord lookup rules
  Router::ConfigurationRef conf = New refcounted< Router::Configuration >();
  ref< RouterConfigGenerator > routerConfigGenerator = New refcounted< RouterConfigGenerator >(ctxt, conf, false, true, datalogFile);

  routerConfigGenerator->createTables(LOCAL);

  ref< Udp > udp = New refcounted< Udp > (LOCAL, 10000);
  ref< Udp > bootstrapUdp = New refcounted< Udp > ("Bootstrap", 9999);
  routerConfigGenerator->configureRouter(udp, LOCAL);

  // populate the finger entries
  initializeBaseTables(ctxt, routerConfigGenerator);
  //sendSuccessorStream(bootstrapUdp, conf);

  RouterRef router = New refcounted< Router >(conf, level);
  if (router->initialize(router) == 0) {
    std::cout << "Correctly initialized network of chord lookup flows.\n";
  } else {
    std::cout << "** Failed to initialize correct spec\n";
    return;
  }

  // Activate the router
  router->activate();

  // Run the router
  amain();
}

int main(int argc, char **argv)
{
  std::cout << "\nTranslated Chord\n";

  if (argc < 2) {
    std::cerr << "Usage: ./chordDatalog file [loglevel seed]\n";
    return 1;
  }

  ref< OL_Context > ctxt = New refcounted< OL_Context>();
  strbuf filename;
  filename << argv[1];
  str file(filename);
  std::ifstream istr(file);
  ctxt->parse_stream(&istr);

  LoggerI::Level level = LoggerI::WARN;

  if (argc > 2) {
    str levelName(argv[2]);
    level = LoggerI::levelFromName[levelName];
  }

  int seed = 0;
  if (argc > 3) {
    seed = atoi(argv[3]);
  }
  srand(seed);

  startChord(level, ctxt, file);
  return 0;
}

<|endoftext|>


<commit_before>#ifndef HAVE_LLVM
#error "This code needs LLVM enabled"
#endif

#include <set>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <cassert>
#include <cstdio>

// ignore unused parameters in LLVM libraries
#if (__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
#else
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif

#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/Instructions.h>
#include <llvm/Support/SourceMgr.h>
#include <llvm/Support/raw_os_ostream.h>
#include <llvm/IRReader/IRReader.h>

#if LLVM_VERSION_MAJOR >= 4
#include <llvm/Bitcode/BitcodeReader.h>
#include <llvm/Bitcode/BitcodeWriter.h>
#else
#include <llvm/Bitcode/ReaderWriter.h>
#endif

#if (__clang__)
#pragma clang diagnostic pop // ignore -Wunused-parameter
#else
#pragma GCC diagnostic pop
#endif

#include "dg/analysis/PointsTo/PointerAnalysisFI.h"
#include "dg/analysis/PointsTo/PointerAnalysisFS.h"
#include "dg/analysis/PointsTo/Pointer.h"

#include "dg/llvm/analysis/PointsTo/PointerAnalysis.h"
#include "dg/llvm/analysis/ReachingDefinitions/ReachingDefinitions.h"

#include "TimeMeasure.h"

using namespace dg;
using namespace dg::analysis;
using namespace dg::analysis::rd;
using llvm::errs;

static bool verbose = false;
static const char *entryFunc = "main";

static std::string
getInstName(const llvm::Value *val)
{
    std::ostringstream ostr;
    llvm::raw_os_ostream ro(ostr);

    assert(val);
    ro << *val;
    ro.flush();

    // break the string if it is too long
    return ostr.str();
}

static void printRDNodeType(enum RDNodeType type)
{
#define ELEM(t) case(t): do {printf("%s", #t); }while(0); break;
    switch(type) {
        ELEM(RDNodeType::ALLOC)
        ELEM(RDNodeType::DYN_ALLOC)
        ELEM(RDNodeType::STORE)
        ELEM(RDNodeType::PHI)
        ELEM(RDNodeType::CALL)
        ELEM(RDNodeType::CALL_RETURN)
        ELEM(RDNodeType::FORK)
        ELEM(RDNodeType::JOIN)
        ELEM(RDNodeType::RETURN)
        ELEM(RDNodeType::NOOP)
        ELEM(RDNodeType::NONE)
        default:
            printf("unknown reaching definitions subgraph type");
    };
#undef ELEM
}

static inline void printAddress(RDNode *node, bool dot)
{
    if (dot)
        printf(" [%p]\\n", static_cast<void*>(node));
    else
        printf(" [%p]\n", static_cast<void*>(node));
}

static void
printName(RDNode *node, bool dot)
{
    if (node == rd::UNKNOWN_MEMORY) {
        printf("UNKNOWN MEMORY");
        return;
    }

    const char *name = nullptr;
#if 0
#ifdef DEBUG_ENABLED
    name = node->getName();
#endif
#endif
    std::string nm;
    if (!name) {
        if (!node->getUserData<llvm::Value>()) {
            printRDNodeType(node->getType());
            printAddress(node, dot);
            return;
        }

        nm = getInstName(node->getUserData<llvm::Value>());
        name = nm.c_str();
    }

    // escape the " character
    for (int i = 0; name[i] != '\0'; ++i) {
        // crop long names
        if (i >= 70) {
            printf(" ...");
            break;
        }

        if (name[i] == '"')
            putchar('\\');

        putchar(name[i]);
    }
}

static void
dumpMap(RDNode *node, bool dot = false)
{
    RDMap& map = node->def_map;
    for (const auto& it : map) {
        for (RDNode *site : it.second) {
            printName(it.first.target, dot);
            // don't print offsets with unknown memory
            if (it.first.target == rd::UNKNOWN_MEMORY) {
                printf(" => ");
            } else {
                if (it.first.offset.isUnknown())
                    printf(" | UNKNOWN | => ");
                else if (it.first.len.isUnknown())
                    printf(" | %lu - UNKNOWN | => ", *it.first.offset);
                else
                    printf(" | %lu - %lu | => ", *it.first.offset,
                           *it.first.offset + *it.first.len - 1);
            }

            printName(site, dot);
            if (dot)
                printf("\\n");
            else
                putchar('\n');
        }
    }
}

template <typename T>
static void printInterval(T& I, const char *pref = nullptr,
                          const char *suff = nullptr) {
    if (pref)
        printf("%s", pref);

    if (I.start.isUnknown())
        printf("[? - ");
    else
        printf("[%lu - ", *I.start);

    if (I.end.isUnknown())
        printf("?]");
    else
        printf("%lu]", *I.end);

    if (suff)
        printf("%s", suff);
}

static void
dumpDDIMap(RDBBlock *block, bool dot = false)
{
    auto& map = block->definitions;
    for (const auto& it : map) {
       printf("\\l----  ");
       printName(it.first, dot);
       printf("  ----\\l");
       for (auto& it2 : it.second) {
           printInterval(it2.first, "  ", " => \\l");
           for (auto where : it2.second) {
               printf("      ");
               printName(where, dot);
               if (dot)
                   printf("\\n");
               else
                   putchar('\n');
           }
       }
    }
}

static void
dumpDefSites(const std::set<DefSite>& defs, const char *kind, bool dot = false)
{
    printf("-------------\\n");
    for (const DefSite& def : defs) {
        printf("%s: ", kind);
        printName(def.target, dot);
            if (def.offset.isUnknown())
                printf(" [? - ");
            else
                printf(" [%lu - ", *def.offset);

            if (def.len.isUnknown())
                printf("?]");
            else
                printf("%lu]", *def.offset + (*def.len - 1));

            if (dot)
                printf("\\n");
            else
                putchar('\n');
    }
}

static void
dumpDefines(RDNode *node, bool dot = false)
{
    if (!node->getDefines().empty())
        dumpDefSites(node->getDefines(), "DEF", dot);
}

static void
dumpOverwrites(RDNode *node, bool dot = false)
{
    if (!node->getOverwrites().empty())
        dumpDefSites(node->getOverwrites(), "DEF strong", dot);
}

static void
dumpUses(RDNode *node, bool dot = false)
{
    if (!node->getUses().empty())
        dumpDefSites(node->getUses(), "USE", dot);
}

static void
dumpRDNode(RDNode *n)
{
    printf("NODE: ");
    printName(n, false);
    if (n->getSize() > 0)
        printf(" [size: %lu]", n->getSize());
    putchar('\n');
    dumpMap(n);
    printf("---\n");
}

static void nodeToDot(RDNode *node) {
    printf("\tNODE%p [label=\"%u ", static_cast<void*>(node), node->getID());
    printName(node, true);
    if (node->getSize() > 0) {
        printf("\\n[size: %lu]\\n", node->getSize());
        printf("\\n-------------\\n");
    }

    if (verbose) {
        printf("\\nblock: %p\\n", node->getBBlock());
        printf("\\n-------------\\n");

        dumpDefines(node, true);
        dumpOverwrites(node, true);
        dumpUses(node, true);
        printf("\\n-------------\\n");
    }

    dumpMap(node, true /* dot */);

    printf("\" shape=box]\n");

}

static void dumpDotOnlyNodes(LLVMReachingDefinitions *RD)
{
    const auto& nodes = RD->getNodes();
    // dump nodes
    for(RDNode *node : nodes) {
        nodeToDot(node);
    }

    // dump def-use edges
    for(RDNode *node : nodes) {
        if (node->isUse()) {
            for (RDNode *def : RD->getReachingDefinitions(node)) {
                printf("\tNODE%p->NODE%p [style=dotted]",
                       static_cast<void*>(def), static_cast<void*>(node));
            }
        }
    }
}

static void dumpDotWithBlocks(LLVMReachingDefinitions *RD) {

    for (auto I = RD->getGraph()->blocks_begin(),
              E = RD->getGraph()->blocks_end(); I != E; ++I) {
        printf("subgraph cluster_%p {\n", *I);
        /* dump nodes */
        for(RDNode *node : I->getNodes()) {
            nodeToDot(node);
        }

        // dump def-use edges
        for(RDNode *node : I->getNodes()) {
            for (RDNode *def : node->defuse) {
                printf("\tNODE%p->NODE%p [style=dotted]",
                       static_cast<void*>(def), static_cast<void*>(node));
            }
        }
        printf("label=\"\\nblock: %p\\n", *I);
        dumpDDIMap(*I, true);
        printf("\"\nlabelloc=b\n");
        printf("}\n");
    }

    /* dump block edges
    for (auto I = RD->getGraph()->blocks_begin(),
              E = RD->getGraph()->blocks_end(); I != E; ++I) {
        for (auto succ : I->getSuccessors())
            printf("\tNODE%p -> NODE%p [penwidth=2]\n",
                   static_cast<void*>(*I),
                   static_cast<void*>(succ));
    }
    */
}

static void
dumpRDdot(LLVMReachingDefinitions *RD)
{

    printf("digraph \"Reaching Definitions Subgraph\" {\n");

    if (RD->getGraph()->getBBlocks().empty())
        dumpDotOnlyNodes(RD);
    else
        dumpDotWithBlocks(RD);

    /* dump edges */
    for (RDNode *node : RD->getNodes()) {
        for (RDNode *succ : node->getSuccessors())
            printf("\tNODE%p -> NODE%p [penwidth=2]\n",
                   static_cast<void*>(node),
                   static_cast<void*>(succ));
    }

    printf("}\n");
}

static void
dumpRD(LLVMReachingDefinitions *RD, bool todot)
{
    assert(RD);

    if (todot)
        dumpRDdot(RD);
    else {
        for (RDNode *node : RD->getNodes())
            dumpRDNode(node);
    }
}

int main(int argc, char *argv[])
{
    llvm::Module *M;
    llvm::LLVMContext context;
    llvm::SMDiagnostic SMD;
    bool todot = false;
    bool threads = false;
    const char *module = nullptr;
    Offset::type field_senitivity = Offset::UNKNOWN;
    bool rd_strong_update_unknown = false;
    Offset::type max_set_size = Offset::UNKNOWN;

    enum {
        FLOW_SENSITIVE = 1,
        FLOW_INSENSITIVE,
    } type = FLOW_INSENSITIVE;

    enum class RdaType {
        DENSE,
        SEMISPARSE
    } rda = RdaType::DENSE;

    // parse options
    for (int i = 1; i < argc; ++i) {
        // run given points-to analysis
        if (strcmp(argv[i], "-pta") == 0) {
            if (strcmp(argv[i+1], "fs") == 0)
                type = FLOW_SENSITIVE;
        } else if (strcmp(argv[i], "-rda") == 0) {
            if (strcmp(argv[i+1], "ss") == 0)
                rda = RdaType::SEMISPARSE;
        } else if (strcmp(argv[i], "-pta-field-sensitive") == 0) {
            field_senitivity = static_cast<Offset::type>(atoll(argv[i + 1]));
        } else if (strcmp(argv[i], "-rd-max-set-size") == 0) {
            max_set_size = static_cast<Offset::type>(atoll(argv[i + 1]));
            if (max_set_size == 0) {
                llvm::errs() << "Invalid -rd-max-set-size argument\n";
                abort();
            }
        } else if (strcmp(argv[i], "-rd-strong-update-unknown") == 0) {
            rd_strong_update_unknown = true;
        } else if (strcmp(argv[i], "-dot") == 0) {
            todot = true;
        } else if (strcmp(argv[i], "-threads") == 0) {
            threads = true;
        } else if (strcmp(argv[i], "-v") == 0) {
            verbose = true;
        } else if (strcmp(argv[i], "-entry") == 0) {
            entryFunc = argv[i+1];
        } else {
            module = argv[i];
        }
    }

    if (!module) {
        errs() << "Usage: % IR_module [-pts fs|fi] [-dot] [-v] [output_file]\n";
        return 1;
    }

#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR <= 5))
    M = llvm::ParseIRFile(module, SMD, context);
#else
    auto _M = llvm::parseIRFile(module, SMD, context);
    // _M is unique pointer, we need to get Module *
    M = _M.get();
#endif

    if (!M) {
        llvm::errs() << "Failed parsing '" << module << "' file:\n";
        SMD.print(argv[0], errs());
        return 1;
    }

    debug::TimeMeasure tm;

    LLVMPointerAnalysis PTA(M, entryFunc, field_senitivity, threads);

    tm.start();

    if (type == FLOW_INSENSITIVE) {
        PTA.run<pta::PointerAnalysisFI>();
    } else {
        PTA.run<pta::PointerAnalysisFS>();
    }

    tm.stop();
    tm.report("INFO: Points-to analysis took");

    LLVMReachingDefinitionsAnalysisOptions opts;
    opts.threads = threads;
    opts.entryFunction = entryFunc;
    opts.strongUpdateUnknown = rd_strong_update_unknown;
    opts.maxSetSize = max_set_size;

    LLVMReachingDefinitions RD(M, &PTA, opts);
    tm.start();
    if (rda == RdaType::SEMISPARSE) {
        RD.run<dg::analysis::rd::SSAReachingDefinitionsAnalysis>();
    } else
        RD.run<dg::analysis::rd::ReachingDefinitionsAnalysis>();
    tm.stop();
    tm.report("INFO: Reaching definitions analysis took");

    dumpRD(&RD, todot);

    return 0;
}
<commit_msg>llvm-rd-dump: rename ss -> ssa, dense -> dataflow<commit_after>#ifndef HAVE_LLVM
#error "This code needs LLVM enabled"
#endif

#include <set>
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <cassert>
#include <cstdio>

// ignore unused parameters in LLVM libraries
#if (__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
#else
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif

#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/Instructions.h>
#include <llvm/Support/SourceMgr.h>
#include <llvm/Support/raw_os_ostream.h>
#include <llvm/IRReader/IRReader.h>

#if LLVM_VERSION_MAJOR >= 4
#include <llvm/Bitcode/BitcodeReader.h>
#include <llvm/Bitcode/BitcodeWriter.h>
#else
#include <llvm/Bitcode/ReaderWriter.h>
#endif

#if (__clang__)
#pragma clang diagnostic pop // ignore -Wunused-parameter
#else
#pragma GCC diagnostic pop
#endif

#include "dg/analysis/PointsTo/PointerAnalysisFI.h"
#include "dg/analysis/PointsTo/PointerAnalysisFS.h"
#include "dg/analysis/PointsTo/Pointer.h"

#include "dg/llvm/analysis/PointsTo/PointerAnalysis.h"
#include "dg/llvm/analysis/ReachingDefinitions/ReachingDefinitions.h"

#include "TimeMeasure.h"

using namespace dg;
using namespace dg::analysis;
using namespace dg::analysis::rd;
using llvm::errs;

static bool verbose = false;
static const char *entryFunc = "main";

static std::string
getInstName(const llvm::Value *val)
{
    std::ostringstream ostr;
    llvm::raw_os_ostream ro(ostr);

    assert(val);
    ro << *val;
    ro.flush();

    // break the string if it is too long
    return ostr.str();
}

static void printRDNodeType(enum RDNodeType type)
{
#define ELEM(t) case(t): do {printf("%s", #t); }while(0); break;
    switch(type) {
        ELEM(RDNodeType::ALLOC)
        ELEM(RDNodeType::DYN_ALLOC)
        ELEM(RDNodeType::STORE)
        ELEM(RDNodeType::PHI)
        ELEM(RDNodeType::CALL)
        ELEM(RDNodeType::CALL_RETURN)
        ELEM(RDNodeType::FORK)
        ELEM(RDNodeType::JOIN)
        ELEM(RDNodeType::RETURN)
        ELEM(RDNodeType::NOOP)
        ELEM(RDNodeType::NONE)
        default:
            printf("unknown reaching definitions subgraph type");
    };
#undef ELEM
}

static inline void printAddress(RDNode *node, bool dot)
{
    if (dot)
        printf(" [%p]\\n", static_cast<void*>(node));
    else
        printf(" [%p]\n", static_cast<void*>(node));
}

static void
printName(RDNode *node, bool dot)
{
    if (node == rd::UNKNOWN_MEMORY) {
        printf("UNKNOWN MEMORY");
        return;
    }

    const char *name = nullptr;
#if 0
#ifdef DEBUG_ENABLED
    name = node->getName();
#endif
#endif
    std::string nm;
    if (!name) {
        if (!node->getUserData<llvm::Value>()) {
            printRDNodeType(node->getType());
            printAddress(node, dot);
            return;
        }

        nm = getInstName(node->getUserData<llvm::Value>());
        name = nm.c_str();
    }

    // escape the " character
    for (int i = 0; name[i] != '\0'; ++i) {
        // crop long names
        if (i >= 70) {
            printf(" ...");
            break;
        }

        if (name[i] == '"')
            putchar('\\');

        putchar(name[i]);
    }
}

static void
dumpMap(RDNode *node, bool dot = false)
{
    RDMap& map = node->def_map;
    for (const auto& it : map) {
        for (RDNode *site : it.second) {
            printName(it.first.target, dot);
            // don't print offsets with unknown memory
            if (it.first.target == rd::UNKNOWN_MEMORY) {
                printf(" => ");
            } else {
                if (it.first.offset.isUnknown())
                    printf(" | UNKNOWN | => ");
                else if (it.first.len.isUnknown())
                    printf(" | %lu - UNKNOWN | => ", *it.first.offset);
                else
                    printf(" | %lu - %lu | => ", *it.first.offset,
                           *it.first.offset + *it.first.len - 1);
            }

            printName(site, dot);
            if (dot)
                printf("\\n");
            else
                putchar('\n');
        }
    }
}

template <typename T>
static void printInterval(T& I, const char *pref = nullptr,
                          const char *suff = nullptr) {
    if (pref)
        printf("%s", pref);

    if (I.start.isUnknown())
        printf("[? - ");
    else
        printf("[%lu - ", *I.start);

    if (I.end.isUnknown())
        printf("?]");
    else
        printf("%lu]", *I.end);

    if (suff)
        printf("%s", suff);
}

static void
dumpDDIMap(RDBBlock *block, bool dot = false)
{
    auto& map = block->definitions;
    for (const auto& it : map) {
       printf("\\l----  ");
       printName(it.first, dot);
       printf("  ----\\l");
       for (auto& it2 : it.second) {
           printInterval(it2.first, "  ", " => \\l");
           for (auto where : it2.second) {
               printf("      ");
               printName(where, dot);
               if (dot)
                   printf("\\n");
               else
                   putchar('\n');
           }
       }
    }
}

static void
dumpDefSites(const std::set<DefSite>& defs, const char *kind, bool dot = false)
{
    printf("-------------\\n");
    for (const DefSite& def : defs) {
        printf("%s: ", kind);
        printName(def.target, dot);
            if (def.offset.isUnknown())
                printf(" [? - ");
            else
                printf(" [%lu - ", *def.offset);

            if (def.len.isUnknown())
                printf("?]");
            else
                printf("%lu]", *def.offset + (*def.len - 1));

            if (dot)
                printf("\\n");
            else
                putchar('\n');
    }
}

static void
dumpDefines(RDNode *node, bool dot = false)
{
    if (!node->getDefines().empty())
        dumpDefSites(node->getDefines(), "DEF", dot);
}

static void
dumpOverwrites(RDNode *node, bool dot = false)
{
    if (!node->getOverwrites().empty())
        dumpDefSites(node->getOverwrites(), "DEF strong", dot);
}

static void
dumpUses(RDNode *node, bool dot = false)
{
    if (!node->getUses().empty())
        dumpDefSites(node->getUses(), "USE", dot);
}

static void
dumpRDNode(RDNode *n)
{
    printf("NODE: ");
    printName(n, false);
    if (n->getSize() > 0)
        printf(" [size: %lu]", n->getSize());
    putchar('\n');
    dumpMap(n);
    printf("---\n");
}

static void nodeToDot(RDNode *node) {
    printf("\tNODE%p [label=\"%u ", static_cast<void*>(node), node->getID());
    printName(node, true);
    if (node->getSize() > 0) {
        printf("\\n[size: %lu]\\n", node->getSize());
        printf("\\n-------------\\n");
    }

    if (verbose) {
        printf("\\nblock: %p\\n", node->getBBlock());
        printf("\\n-------------\\n");

        dumpDefines(node, true);
        dumpOverwrites(node, true);
        dumpUses(node, true);
        printf("\\n-------------\\n");
    }

    dumpMap(node, true /* dot */);

    printf("\" shape=box]\n");

}

static void dumpDotOnlyNodes(LLVMReachingDefinitions *RD)
{
    const auto& nodes = RD->getNodes();
    // dump nodes
    for(RDNode *node : nodes) {
        nodeToDot(node);
    }

    // dump def-use edges
    for(RDNode *node : nodes) {
        if (node->isUse()) {
            for (RDNode *def : RD->getReachingDefinitions(node)) {
                printf("\tNODE%p->NODE%p [style=dotted]",
                       static_cast<void*>(def), static_cast<void*>(node));
            }
        }
    }
}

static void dumpDotWithBlocks(LLVMReachingDefinitions *RD) {

    for (auto I = RD->getGraph()->blocks_begin(),
              E = RD->getGraph()->blocks_end(); I != E; ++I) {
        printf("subgraph cluster_%p {\n", *I);
        /* dump nodes */
        for(RDNode *node : I->getNodes()) {
            nodeToDot(node);
        }

        // dump def-use edges
        for(RDNode *node : I->getNodes()) {
            for (RDNode *def : node->defuse) {
                printf("\tNODE%p->NODE%p [style=dotted]",
                       static_cast<void*>(def), static_cast<void*>(node));
            }
        }
        printf("label=\"\\nblock: %p\\n", *I);
        dumpDDIMap(*I, true);
        printf("\"\nlabelloc=b\n");
        printf("}\n");
    }

    /* dump block edges
    for (auto I = RD->getGraph()->blocks_begin(),
              E = RD->getGraph()->blocks_end(); I != E; ++I) {
        for (auto succ : I->getSuccessors())
            printf("\tNODE%p -> NODE%p [penwidth=2]\n",
                   static_cast<void*>(*I),
                   static_cast<void*>(succ));
    }
    */
}

static void
dumpRDdot(LLVMReachingDefinitions *RD)
{

    printf("digraph \"Reaching Definitions Subgraph\" {\n");

    if (RD->getGraph()->getBBlocks().empty())
        dumpDotOnlyNodes(RD);
    else
        dumpDotWithBlocks(RD);

    /* dump edges */
    for (RDNode *node : RD->getNodes()) {
        for (RDNode *succ : node->getSuccessors())
            printf("\tNODE%p -> NODE%p [penwidth=2]\n",
                   static_cast<void*>(node),
                   static_cast<void*>(succ));
    }

    printf("}\n");
}

static void
dumpRD(LLVMReachingDefinitions *RD, bool todot)
{
    assert(RD);

    if (todot)
        dumpRDdot(RD);
    else {
        for (RDNode *node : RD->getNodes())
            dumpRDNode(node);
    }
}

int main(int argc, char *argv[])
{
    llvm::Module *M;
    llvm::LLVMContext context;
    llvm::SMDiagnostic SMD;
    bool todot = false;
    bool threads = false;
    const char *module = nullptr;
    Offset::type field_senitivity = Offset::UNKNOWN;
    bool rd_strong_update_unknown = false;
    Offset::type max_set_size = Offset::UNKNOWN;

    enum {
        FLOW_SENSITIVE = 1,
        FLOW_INSENSITIVE,
    } type = FLOW_INSENSITIVE;

    enum class RdaType {
        DATAFLOW,
        SSA
    } rda = RdaType::DATAFLOW;

    // parse options
    for (int i = 1; i < argc; ++i) {
        // run given points-to analysis
        if (strcmp(argv[i], "-pta") == 0) {
            if (strcmp(argv[i+1], "fs") == 0)
                type = FLOW_SENSITIVE;
        } else if (strcmp(argv[i], "-rda") == 0) {
            if (strcmp(argv[i+1], "ssa") == 0)
                rda = RdaType::SSA;
        } else if (strcmp(argv[i], "-pta-field-sensitive") == 0) {
            field_senitivity = static_cast<Offset::type>(atoll(argv[i + 1]));
        } else if (strcmp(argv[i], "-rd-max-set-size") == 0) {
            max_set_size = static_cast<Offset::type>(atoll(argv[i + 1]));
            if (max_set_size == 0) {
                llvm::errs() << "Invalid -rd-max-set-size argument\n";
                abort();
            }
        } else if (strcmp(argv[i], "-rd-strong-update-unknown") == 0) {
            rd_strong_update_unknown = true;
        } else if (strcmp(argv[i], "-dot") == 0) {
            todot = true;
        } else if (strcmp(argv[i], "-threads") == 0) {
            threads = true;
        } else if (strcmp(argv[i], "-v") == 0) {
            verbose = true;
        } else if (strcmp(argv[i], "-entry") == 0) {
            entryFunc = argv[i+1];
        } else {
            module = argv[i];
        }
    }

    if (!module) {
        errs() << "Usage: % IR_module [-pts fs|fi] [-dot] [-v] [output_file]\n";
        return 1;
    }

#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR <= 5))
    M = llvm::ParseIRFile(module, SMD, context);
#else
    auto _M = llvm::parseIRFile(module, SMD, context);
    // _M is unique pointer, we need to get Module *
    M = _M.get();
#endif

    if (!M) {
        llvm::errs() << "Failed parsing '" << module << "' file:\n";
        SMD.print(argv[0], errs());
        return 1;
    }

    debug::TimeMeasure tm;

    LLVMPointerAnalysis PTA(M, entryFunc, field_senitivity, threads);

    tm.start();

    if (type == FLOW_INSENSITIVE) {
        PTA.run<pta::PointerAnalysisFI>();
    } else {
        PTA.run<pta::PointerAnalysisFS>();
    }

    tm.stop();
    tm.report("INFO: Points-to analysis took");

    LLVMReachingDefinitionsAnalysisOptions opts;
    opts.threads = threads;
    opts.entryFunction = entryFunc;
    opts.strongUpdateUnknown = rd_strong_update_unknown;
    opts.maxSetSize = max_set_size;

    LLVMReachingDefinitions RD(M, &PTA, opts);
    tm.start();
    if (rda == RdaType::SSA) {
        RD.run<dg::analysis::rd::SSAReachingDefinitionsAnalysis>();
    } else
        RD.run<dg::analysis::rd::ReachingDefinitionsAnalysis>();
    tm.stop();
    tm.report("INFO: Reaching definitions analysis took");

    dumpRD(&RD, todot);

    return 0;
}
<|endoftext|>