Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b675f7cd authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "debuggerd: Dump list of open files on process crash."

parents 1abc3cd6 53fb32f0
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ LOCAL_SRC_FILES:= \
    debuggerd.cpp \
    elf_utils.cpp \
    getevent.cpp \
    open_files_list.cpp \
    signal_sender.cpp \
    tombstone.cpp \
    utility.cpp \
@@ -108,9 +109,11 @@ include $(BUILD_EXECUTABLE)

debuggerd_test_src_files := \
    utility.cpp \
    open_files_list.cpp \
    test/dump_memory_test.cpp \
    test/elf_fake.cpp \
    test/log_fake.cpp \
    test/open_files_list_test.cpp \
    test/property_fake.cpp \
    test/ptrace_fake.cpp \
    test/tombstone_test.cpp \
+13 −5
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@

#include "backtrace.h"
#include "getevent.h"
#include "open_files_list.h"
#include "signal_sender.h"
#include "tombstone.h"
#include "utility.h"
@@ -452,7 +453,8 @@ static void ptrace_siblings(pid_t pid, pid_t main_tid, pid_t ignore_tid, std::se
}

static bool perform_dump(const debugger_request_t& request, int fd, int tombstone_fd,
                         BacktraceMap* backtrace_map, const std::set<pid_t>& siblings,
                         BacktraceMap* backtrace_map, const OpenFilesList& open_files,
                         const std::set<pid_t>& siblings,
                         int* crash_signal, std::string* amfd_data) {
  if (TEMP_FAILURE_RETRY(write(fd, "\0", 1)) != 1) {
    ALOGE("debuggerd: failed to respond to client: %s\n", strerror(errno));
@@ -471,7 +473,8 @@ static bool perform_dump(const debugger_request_t& request, int fd, int tombston
      case SIGSTOP:
        if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
          ALOGV("debuggerd: stopped -- dumping to tombstone");
          engrave_tombstone(tombstone_fd, backtrace_map, request.pid, request.tid, siblings,
          engrave_tombstone(tombstone_fd, backtrace_map, open_files,
                            request.pid, request.tid, siblings,
                            request.abort_msg_address, amfd_data);
        } else if (request.action == DEBUGGER_ACTION_DUMP_BACKTRACE) {
          ALOGV("debuggerd: stopped -- dumping to fd");
@@ -498,7 +501,8 @@ static bool perform_dump(const debugger_request_t& request, int fd, int tombston
      case SIGTRAP:
        ALOGV("stopped -- fatal signal\n");
        *crash_signal = signal;
        engrave_tombstone(tombstone_fd, backtrace_map, request.pid, request.tid, siblings,
        engrave_tombstone(tombstone_fd, backtrace_map, open_files,
                          request.pid, request.tid, siblings,
                          request.abort_msg_address, amfd_data);
        break;

@@ -593,6 +597,10 @@ static void worker_process(int fd, debugger_request_t& request) {
  // Generate the backtrace map before dropping privileges.
  std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(request.pid));

  // Collect the list of open files before dropping privileges.
  OpenFilesList open_files;
  populate_open_files_list(request.pid, &open_files);

  int amfd = -1;
  std::unique_ptr<std::string> amfd_data;
  if (request.action == DEBUGGER_ACTION_CRASH) {
@@ -610,8 +618,8 @@ static void worker_process(int fd, debugger_request_t& request) {
  }

  int crash_signal = SIGKILL;
  succeeded = perform_dump(request, fd, tombstone_fd, backtrace_map.get(), siblings,
                           &crash_signal, amfd_data.get());
  succeeded = perform_dump(request, fd, tombstone_fd, backtrace_map.get(), open_files,
                           siblings, &crash_signal, amfd_data.get());
  if (succeeded) {
    if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
      if (!tombstone_path.empty()) {
+69 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define LOG_TAG "DEBUG"

#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>

#include <string>
#include <utility>
#include <vector>

#include <android-base/file.h>
#include <android/log.h>

#include "open_files_list.h"

#include "utility.h"

void populate_open_files_list(pid_t pid, OpenFilesList* list) {
  std::string fd_dir_name = "/proc/" + std::to_string(pid) + "/fd";
  std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(fd_dir_name.c_str()), closedir);
  if (dir == nullptr) {
    ALOGE("failed to open directory %s: %s", fd_dir_name.c_str(), strerror(errno));
    return;
  }

  struct dirent* de;
  while ((de = readdir(dir.get())) != nullptr) {
    if (*de->d_name == '.') {
      continue;
    }

    int fd = atoi(de->d_name);
    std::string path = fd_dir_name + "/" + std::string(de->d_name);
    std::string target;
    if (android::base::Readlink(path, &target)) {
      list->emplace_back(fd, target);
    } else {
      ALOGE("failed to readlink %s: %s", path.c_str(), strerror(errno));
      list->emplace_back(fd, "???");
    }
  }
}

void dump_open_files_list_to_log(const OpenFilesList& files, log_t* log, const char* prefix) {
  for (auto& file : files) {
    _LOG(log, logtype::OPEN_FILES, "%sfd %i: %s\n", prefix, file.first, file.second.c_str());
  }
}
+36 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef _DEBUGGERD_OPEN_FILES_LIST_H
#define _DEBUGGERD_OPEN_FILES_LIST_H

#include <sys/types.h>

#include <string>
#include <utility>
#include <vector>

#include "utility.h"

typedef std::vector<std::pair<int, std::string>> OpenFilesList;

/* Populates the given list with open files for the given process. */
void populate_open_files_list(pid_t pid, OpenFilesList* list);

/* Dumps the open files list to the log. */
void dump_open_files_list_to_log(const OpenFilesList& files, log_t* log, const char* prefix);

#endif // _DEBUGGERD_OPEN_FILES_LIST_H
+49 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <string>

#include <gtest/gtest.h>

#include "android-base/test_utils.h"

#include "open_files_list.h"

// Check that we can produce a list of open files for the current process, and
// that it includes a known open file.
TEST(OpenFilesListTest, BasicTest) {
  // Open a temporary file that we can check for in the list of open files.
  TemporaryFile tf;

  // Get the list of open files for this process.
  OpenFilesList list;
  populate_open_files_list(getpid(), &list);

  // Verify our open file is in the list.
  bool found = false;
  for (auto&  file : list) {
    if (file.first == tf.fd) {
      EXPECT_EQ(file.second, std::string(tf.path));
      found = true;
      break;
    }
  }
  EXPECT_TRUE(found);
}
Loading