<commit_before>// Copyright (c) 2006, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <cassert>
#include <cstdio>

#include "google_breakpad/processor/minidump_processor.h"
#include "google_breakpad/processor/call_stack.h"
#include "google_breakpad/processor/minidump.h"
#include "google_breakpad/processor/process_state.h"
#include "processor/logging.h"
#include "processor/scoped_ptr.h"
#include "processor/stackwalker_x86.h"

namespace google_breakpad {

MinidumpProcessor::MinidumpProcessor(SymbolSupplier *supplier,
                                     SourceLineResolverInterface *resolver)
    : supplier_(supplier), resolver_(resolver) {
}

MinidumpProcessor::~MinidumpProcessor() {
}

ProcessResult MinidumpProcessor::Process(
    Minidump *dump, ProcessState *process_state) {
  assert(dump);
  assert(process_state);

  process_state->Clear();

  const MDRawHeader *header = dump->header();
  if (!header) {
    BPLOG(ERROR) << "Minidump " << dump->path() << " has no header";
    return PROCESS_ERROR_NO_MINIDUMP_HEADER;
  }
  process_state->time_date_stamp_ = header->time_date_stamp;

  bool has_cpu_info = GetCPUInfo(dump, &process_state->system_info_);
  bool has_os_info = GetOSInfo(dump, &process_state->system_info_);

  u_int32_t dump_thread_id = 0;
  bool has_dump_thread = false;
  u_int32_t requesting_thread_id = 0;
  bool has_requesting_thread = false;

  MinidumpBreakpadInfo *breakpad_info = dump->GetBreakpadInfo();
  if (breakpad_info) {
    has_dump_thread = breakpad_info->GetDumpThreadID(&dump_thread_id);
    has_requesting_thread =
        breakpad_info->GetRequestingThreadID(&requesting_thread_id);
  }

  MinidumpException *exception = dump->GetException();
  if (exception) {
    process_state->crashed_ = true;
    has_requesting_thread = exception->GetThreadID(&requesting_thread_id);

    process_state->crash_reason_ = GetCrashReason(
        dump, &process_state->crash_address_);
  }

  MinidumpModuleList *module_list = dump->GetModuleList();

  // Put a copy of the module list into ProcessState object.  This is not
  // necessarily a MinidumpModuleList, but it adheres to the CodeModules
  // interface, which is all that ProcessState needs to expose.
  if (module_list)
    process_state->modules_ = module_list->Copy();

  MinidumpThreadList *threads = dump->GetThreadList();
  if (!threads) {
    BPLOG(ERROR) << "Minidump " << dump->path() << " has no thread list";
    return PROCESS_ERROR_NO_THREAD_LIST;
  }

  BPLOG(INFO) << "Minidump " << dump->path() << " has " <<
      (has_cpu_info           ? "" : "no ") << "CPU info, " <<
      (has_os_info            ? "" : "no ") << "OS info, " <<
      (breakpad_info != NULL  ? "" : "no ") << "Breakpad info, " <<
      (exception != NULL      ? "" : "no ") << "exception, " <<
      (module_list != NULL    ? "" : "no ") << "module list, " <<
      (threads != NULL        ? "" : "no ") << "thread list, " <<
      (has_dump_thread        ? "" : "no ") << "dump thread, and " <<
      (has_requesting_thread  ? "" : "no ") << "requesting thread";

  bool interrupted = false;
  bool found_requesting_thread = false;
  unsigned int thread_count = threads->thread_count();
  for (unsigned int thread_index = 0;
       thread_index < thread_count;
       ++thread_index) {
    char thread_string_buffer[64];
    snprintf(thread_string_buffer, sizeof(thread_string_buffer), "%d/%d",
             thread_index, thread_count);
    string thread_string = dump->path() + ":" + thread_string_buffer;

    MinidumpThread *thread = threads->GetThreadAtIndex(thread_index);
    if (!thread) {
      BPLOG(ERROR) << "Could not get thread for " << thread_string;
      return PROCESS_ERROR_GETTING_THREAD;
    }

    u_int32_t thread_id;
    if (!thread->GetThreadID(&thread_id)) {
      BPLOG(ERROR) << "Could not get thread ID for " << thread_string;
      return PROCESS_ERROR_GETTING_THREAD_ID;
    }

    thread_string += " id " + HexString(thread_id);
    BPLOG(INFO) << "Looking at thread " << thread_string;

    // If this thread is the thread that produced the minidump, don't process
    // it.  Because of the problems associated with a thread producing a
    // dump of itself (when both its context and its stack are in flux),
    // processing that stack wouldn't provide much useful data.
    if (has_dump_thread && thread_id == dump_thread_id) {
      continue;
    }

    MinidumpContext *context = thread->GetContext();

    if (has_requesting_thread && thread_id == requesting_thread_id) {
      if (found_requesting_thread) {
        // There can't be more than one requesting thread.
        BPLOG(ERROR) << "Duplicate requesting thread: " << thread_string;
        return PROCESS_ERROR_DUPLICATE_REQUESTING_THREADS;
      }

      // Use processed_state->threads_.size() instead of thread_index.
      // thread_index points to the thread index in the minidump, which
      // might be greater than the thread index in the threads vector if
      // any of the minidump's threads are skipped and not placed into the
      // processed threads vector.  The thread vector's current size will
      // be the index of the current thread when it's pushed into the
      // vector.
      process_state->requesting_thread_ = process_state->threads_.size();

      found_requesting_thread = true;

      if (process_state->crashed_) {
        // Use the exception record's context for the crashed thread, instead
        // of the thread's own context.  For the crashed thread, the thread's
        // own context is the state inside the exception handler.  Using it
        // would not result in the expected stack trace from the time of the
        // crash. If the exception context is invalid, however, we fall back
        // on the thread context.
        MinidumpContext * ctx = exception->GetContext();
        context = ctx ? ctx : thread->GetContext();
      }
    }

    MinidumpMemoryRegion *thread_memory = thread->GetMemory();
    if (!thread_memory) {
      BPLOG(ERROR) << "No memory region for " << thread_string;
      return PROCESS_ERROR_NO_MEMORY_FOR_THREAD;
    }

    // Use process_state->modules_ instead of module_list, because the
    // |modules| argument will be used to populate the |module| fields in
    // the returned StackFrame objects, which will be placed into the
    // returned ProcessState object.  module_list's lifetime is only as
    // long as the Minidump object: it will be deleted when this function
    // returns.  process_state->modules_ is owned by the ProcessState object
    // (just like the StackFrame objects), and is much more suitable for this
    // task.
    scoped_ptr<Stackwalker> stackwalker(
        Stackwalker::StackwalkerForCPU(process_state->system_info(),
                                       context,
                                       thread_memory,
                                       process_state->modules_,<commit_msg>Fixed style error<commit_after>// Copyright (c) 2006, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <cassert>
#include <cstdio>

#include "google_breakpad/processor/minidump_processor.h"
#include "google_breakpad/processor/call_stack.h"
#include "google_breakpad/processor/minidump.h"
#include "google_breakpad/processor/process_state.h"
#include "processor/logging.h"
#include "processor/scoped_ptr.h"
#include "processor/stackwalker_x86.h"

namespace google_breakpad {

MinidumpProcessor::MinidumpProcessor(SymbolSupplier *supplier,
                                     SourceLineResolverInterface *resolver)
    : supplier_(supplier), resolver_(resolver) {
}

MinidumpProcessor::~MinidumpProcessor() {
}

ProcessResult MinidumpProcessor::Process(
    Minidump *dump, ProcessState *process_state) {
  assert(dump);
  assert(process_state);

  process_state->Clear();

  const MDRawHeader *header = dump->header();
  if (!header) {
    BPLOG(ERROR) << "Minidump " << dump->path() << " has no header";
    return PROCESS_ERROR_NO_MINIDUMP_HEADER;
  }
  process_state->time_date_stamp_ = header->time_date_stamp;

  bool has_cpu_info = GetCPUInfo(dump, &process_state->system_info_);
  bool has_os_info = GetOSInfo(dump, &process_state->system_info_);

  u_int32_t dump_thread_id = 0;
  bool has_dump_thread = false;
  u_int32_t requesting_thread_id = 0;
  bool has_requesting_thread = false;

  MinidumpBreakpadInfo *breakpad_info = dump->GetBreakpadInfo();
  if (breakpad_info) {
    has_dump_thread = breakpad_info->GetDumpThreadID(&dump_thread_id);
    has_requesting_thread =
        breakpad_info->GetRequestingThreadID(&requesting_thread_id);
  }

  MinidumpException *exception = dump->GetException();
  if (exception) {
    process_state->crashed_ = true;
    has_requesting_thread = exception->GetThreadID(&requesting_thread_id);

    process_state->crash_reason_ = GetCrashReason(
        dump, &process_state->crash_address_);
  }

  MinidumpModuleList *module_list = dump->GetModuleList();

  // Put a copy of the module list into ProcessState object.  This is not
  // necessarily a MinidumpModuleList, but it adheres to the CodeModules
  // interface, which is all that ProcessState needs to expose.
  if (module_list)
    process_state->modules_ = module_list->Copy();

  MinidumpThreadList *threads = dump->GetThreadList();
  if (!threads) {
    BPLOG(ERROR) << "Minidump " << dump->path() << " has no thread list";
    return PROCESS_ERROR_NO_THREAD_LIST;
  }

  BPLOG(INFO) << "Minidump " << dump->path() << " has " <<
      (has_cpu_info           ? "" : "no ") << "CPU info, " <<
      (has_os_info            ? "" : "no ") << "OS info, " <<
      (breakpad_info != NULL  ? "" : "no ") << "Breakpad info, " <<
      (exception != NULL      ? "" : "no ") << "exception, " <<
      (module_list != NULL    ? "" : "no ") << "module list, " <<
      (threads != NULL        ? "" : "no ") << "thread list, " <<
      (has_dump_thread        ? "" : "no ") << "dump thread, and " <<
      (has_requesting_thread  ? "" : "no ") << "requesting thread";

  bool interrupted = false;
  bool found_requesting_thread = false;
  unsigned int thread_count = threads->thread_count();
  for (unsigned int thread_index = 0;
       thread_index < thread_count;
       ++thread_index) {
    char thread_string_buffer[64];
    snprintf(thread_string_buffer, sizeof(thread_string_buffer), "%d/%d",
             thread_index, thread_count);
    string thread_string = dump->path() + ":" + thread_string_buffer;

    MinidumpThread *thread = threads->GetThreadAtIndex(thread_index);
    if (!thread) {
      BPLOG(ERROR) << "Could not get thread for " << thread_string;
      return PROCESS_ERROR_GETTING_THREAD;
    }

    u_int32_t thread_id;
    if (!thread->GetThreadID(&thread_id)) {
      BPLOG(ERROR) << "Could not get thread ID for " << thread_string;
      return PROCESS_ERROR_GETTING_THREAD_ID;
    }

    thread_string += " id " + HexString(thread_id);
    BPLOG(INFO) << "Looking at thread " << thread_string;

    // If this thread is the thread that produced the minidump, don't process
    // it.  Because of the problems associated with a thread producing a
    // dump of itself (when both its context and its stack are in flux),
    // processing that stack wouldn't provide much useful data.
    if (has_dump_thread && thread_id == dump_thread_id) {
      continue;
    }

    MinidumpContext *context = thread->GetContext();

    if (has_requesting_thread && thread_id == requesting_thread_id) {
      if (found_requesting_thread) {
        // There can't be more than one requesting thread.
        BPLOG(ERROR) << "Duplicate requesting thread: " << thread_string;
        return PROCESS_ERROR_DUPLICATE_REQUESTING_THREADS;
      }

      // Use processed_state->threads_.size() instead of thread_index.
      // thread_index points to the thread index in the minidump, which
      // might be greater than the thread index in the threads vector if
      // any of the minidump's threads are skipped and not placed into the
      // processed threads vector.  The thread vector's current size will
      // be the index of the current thread when it's pushed into the
      // vector.
      process_state->requesting_thread_ = process_state->threads_.size();

      found_requesting_thread = true;

      if (process_state->crashed_) {
        // Use the exception record's context for the crashed thread, instead
        // of the thread's own context.  For the crashed thread, the thread's
        // own context is the state inside the exception handler.  Using it
        // would not result in the expected stack trace from the time of the
        // crash. If the exception context is invalid, however, we fall back
        // on the thread context.
        MinidumpContext *ctx = exception->GetContext();
        context = ctx ? ctx : thread->GetContext();
      }
    }

    MinidumpMemoryRegion *thread_memory = thread->GetMemory();
    if (!thread_memory) {
      BPLOG(ERROR) << "No memory region for " << thread_string;
      return PROCESS_ERROR_NO_MEMORY_FOR_THREAD;
    }

    // Use process_state->modules_ instead of module_list, because the
    // |modules| argument will be used to populate the |module| fields in
    // the returned StackFrame objects, which will be placed into the
    // returned ProcessState object.  module_list's lifetime is only as
    // long as the Minidump object: it will be deleted when this function
    // returns.  process_state->modules_ is owned by the ProcessState object
    // (just like the StackFrame objects), and is much more suitable for this
    // task.
    scoped_ptr<Stackwalker> stackwalker(
        Stackwalker::StackwalkerForCPU(process_state->system_info(),
                                       context,
                                       thread_memory,
                                       process_state->modules_,
{'fraction_non_alphanumeric': 0.09834116178131874, 'fraction_numerical': 0.0020215232772459717, 'mean_word_length': 3.2453306410903586, 'pattern_counts': {'":': 2, '<': 151, '<?xml version=': 0, '>': 83, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3934891', 'n_tokens_mistral': 4881, 'n_tokens_neox': 4656, 'n_words': 1535}