Merge "Allow fuzzy_fastboot number to run for a specific device serial number" into qt-dev
diff --git a/adb/daemon/shell_service.cpp b/adb/daemon/shell_service.cpp
index e9d9c63..3c8f393 100644
--- a/adb/daemon/shell_service.cpp
+++ b/adb/daemon/shell_service.cpp
@@ -406,11 +406,16 @@
strerror(errno));
return false;
}
- // Raw subprocess + shell protocol allows for splitting stderr.
- if (!CreateSocketpair(&stderr_sfd_, &child_stderr_sfd)) {
- *error = android::base::StringPrintf("failed to create socketpair for stderr: %s",
- strerror(errno));
- return false;
+ if (protocol_ == SubprocessProtocol::kShell) {
+ // Shell protocol allows for splitting stderr.
+ if (!CreateSocketpair(&stderr_sfd_, &child_stderr_sfd)) {
+ *error = android::base::StringPrintf("failed to create socketpair for stderr: %s",
+ strerror(errno));
+ return false;
+ }
+ } else {
+ // Raw protocol doesn't support multiple output streams, so combine stdout and stderr.
+ child_stderr_sfd.reset(dup(child_stdinout_sfd));
}
D("execinprocess: stdin/stdout FD = %d, stderr FD = %d", stdinout_sfd_.get(),
diff --git a/adb/daemon/shell_service_test.cpp b/adb/daemon/shell_service_test.cpp
index 323bcec..dc79d12 100644
--- a/adb/daemon/shell_service_test.cpp
+++ b/adb/daemon/shell_service_test.cpp
@@ -35,7 +35,6 @@
static void SetUpTestCase() {
// This is normally done in main.cpp.
saved_sigpipe_handler_ = signal(SIGPIPE, SIG_IGN);
-
}
static void TearDownTestCase() {
@@ -49,26 +48,32 @@
SubprocessProtocol protocol);
void CleanupTestSubprocess();
- virtual void TearDown() override {
- void CleanupTestSubprocess();
- }
+ void StartTestCommandInProcess(std::string name, Command command, SubprocessProtocol protocol);
+
+ virtual void TearDown() override { CleanupTestSubprocess(); }
static sighandler_t saved_sigpipe_handler_;
- unique_fd subprocess_fd_;
+ unique_fd command_fd_;
};
sighandler_t ShellServiceTest::saved_sigpipe_handler_ = nullptr;
void ShellServiceTest::StartTestSubprocess(
const char* command, SubprocessType type, SubprocessProtocol protocol) {
- subprocess_fd_ = StartSubprocess(command, nullptr, type, protocol);
- ASSERT_TRUE(subprocess_fd_ >= 0);
+ command_fd_ = StartSubprocess(command, nullptr, type, protocol);
+ ASSERT_TRUE(command_fd_ >= 0);
}
void ShellServiceTest::CleanupTestSubprocess() {
}
+void ShellServiceTest::StartTestCommandInProcess(std::string name, Command command,
+ SubprocessProtocol protocol) {
+ command_fd_ = StartCommandInProcess(std::move(name), std::move(command), protocol);
+ ASSERT_TRUE(command_fd_ >= 0);
+}
+
namespace {
// Reads raw data from |fd| until it closes or errors.
@@ -93,7 +98,7 @@
stdout->clear();
stderr->clear();
- ShellProtocol* protocol = new ShellProtocol(fd);
+ auto protocol = std::make_unique<ShellProtocol>(fd);
while (protocol->Read()) {
switch (protocol->id()) {
case ShellProtocol::kIdStdout:
@@ -111,7 +116,6 @@
ADD_FAILURE() << "Unidentified packet ID: " << protocol->id();
}
}
- delete protocol;
return exit_code;
}
@@ -154,7 +158,7 @@
// [ -t 0 ] == 0 means we have a terminal (PTY). Even when requesting a raw subprocess, without
// the shell protocol we should always force a PTY to ensure proper cleanup.
- ExpectLinesEqual(ReadRaw(subprocess_fd_), {"foo", "bar", "0"});
+ ExpectLinesEqual(ReadRaw(command_fd_), {"foo", "bar", "0"});
}
// Tests a PTY subprocess with no protocol.
@@ -165,7 +169,7 @@
SubprocessType::kPty, SubprocessProtocol::kNone));
// [ -t 0 ] == 0 means we have a terminal (PTY).
- ExpectLinesEqual(ReadRaw(subprocess_fd_), {"foo", "bar", "0"});
+ ExpectLinesEqual(ReadRaw(command_fd_), {"foo", "bar", "0"});
}
// Tests a raw subprocess with the shell protocol.
@@ -175,7 +179,7 @@
SubprocessType::kRaw, SubprocessProtocol::kShell));
std::string stdout, stderr;
- EXPECT_EQ(24, ReadShellProtocol(subprocess_fd_, &stdout, &stderr));
+ EXPECT_EQ(24, ReadShellProtocol(command_fd_, &stdout, &stderr));
ExpectLinesEqual(stdout, {"foo", "baz"});
ExpectLinesEqual(stderr, {"bar"});
}
@@ -189,7 +193,7 @@
// PTY always combines stdout and stderr but the shell protocol should
// still give us an exit code.
std::string stdout, stderr;
- EXPECT_EQ(50, ReadShellProtocol(subprocess_fd_, &stdout, &stderr));
+ EXPECT_EQ(50, ReadShellProtocol(command_fd_, &stdout, &stderr));
ExpectLinesEqual(stdout, {"foo", "bar", "baz"});
ExpectLinesEqual(stderr, {});
}
@@ -204,7 +208,7 @@
"echo --${TEST_STR}--",
"exit"};
- ShellProtocol* protocol = new ShellProtocol(subprocess_fd_);
+ ShellProtocol* protocol = new ShellProtocol(command_fd_);
for (std::string command : commands) {
// Interactive shell requires a newline to complete each command.
command.push_back('\n');
@@ -214,7 +218,7 @@
delete protocol;
std::string stdout, stderr;
- EXPECT_EQ(0, ReadShellProtocol(subprocess_fd_, &stdout, &stderr));
+ EXPECT_EQ(0, ReadShellProtocol(command_fd_, &stdout, &stderr));
// An unpredictable command prompt makes parsing exact output difficult but
// it should at least contain echoed input and the expected output.
for (const char* command : commands) {
@@ -230,14 +234,14 @@
SubprocessType::kRaw, SubprocessProtocol::kShell));
std::string input = "foo\nbar";
- ShellProtocol* protocol = new ShellProtocol(subprocess_fd_);
+ ShellProtocol* protocol = new ShellProtocol(command_fd_);
memcpy(protocol->data(), input.data(), input.length());
ASSERT_TRUE(protocol->Write(ShellProtocol::kIdStdin, input.length()));
ASSERT_TRUE(protocol->Write(ShellProtocol::kIdCloseStdin, 0));
delete protocol;
std::string stdout, stderr;
- EXPECT_EQ(0, ReadShellProtocol(subprocess_fd_, &stdout, &stderr));
+ EXPECT_EQ(0, ReadShellProtocol(command_fd_, &stdout, &stderr));
ExpectLinesEqual(stdout, {"foo", "barTEST_DONE"});
ExpectLinesEqual(stderr, {});
}
@@ -249,7 +253,7 @@
SubprocessType::kRaw, SubprocessProtocol::kShell));
std::string stdout, stderr;
- EXPECT_EQ(0, ReadShellProtocol(subprocess_fd_, &stdout, &stderr));
+ EXPECT_EQ(0, ReadShellProtocol(command_fd_, &stdout, &stderr));
ExpectLinesEqual(stdout, {});
ExpectLinesEqual(stderr, {"bar"});
}
@@ -261,7 +265,56 @@
SubprocessType::kRaw, SubprocessProtocol::kShell));
std::string stdout, stderr;
- EXPECT_EQ(0, ReadShellProtocol(subprocess_fd_, &stdout, &stderr));
+ EXPECT_EQ(0, ReadShellProtocol(command_fd_, &stdout, &stderr));
ExpectLinesEqual(stdout, {"foo"});
ExpectLinesEqual(stderr, {});
}
+
+// Tests an inprocess command with no protocol.
+TEST_F(ShellServiceTest, RawNoProtocolInprocess) {
+ ASSERT_NO_FATAL_FAILURE(
+ StartTestCommandInProcess("123",
+ [](auto args, auto in, auto out, auto err) -> int {
+ EXPECT_EQ("123", args);
+ char input[10];
+ EXPECT_TRUE(ReadFdExactly(in, input, 2));
+ input[2] = 0;
+ EXPECT_STREQ("in", input);
+ WriteFdExactly(out, "out\n");
+ WriteFdExactly(err, "err\n");
+ return 0;
+ },
+ SubprocessProtocol::kNone));
+
+ WriteFdExactly(command_fd_, "in");
+ ExpectLinesEqual(ReadRaw(command_fd_), {"out", "err"});
+}
+
+// Tests an inprocess command with the shell protocol.
+TEST_F(ShellServiceTest, RawShellProtocolInprocess) {
+ ASSERT_NO_FATAL_FAILURE(
+ StartTestCommandInProcess("321",
+ [](auto args, auto in, auto out, auto err) -> int {
+ EXPECT_EQ("321", args);
+ char input[10];
+ EXPECT_TRUE(ReadFdExactly(in, input, 2));
+ input[2] = 0;
+ EXPECT_STREQ("in", input);
+ WriteFdExactly(out, "out\n");
+ WriteFdExactly(err, "err\n");
+ return 0;
+ },
+ SubprocessProtocol::kShell));
+
+ {
+ auto write_protocol = std::make_unique<ShellProtocol>(command_fd_);
+ memcpy(write_protocol->data(), "in", 2);
+ write_protocol->Write(ShellProtocol::kIdStdin, 2);
+ }
+
+ std::string stdout, stderr;
+ // For in-process commands the exit code is always the default (1).
+ EXPECT_EQ(1, ReadShellProtocol(command_fd_, &stdout, &stderr));
+ ExpectLinesEqual(stdout, {"out"});
+ ExpectLinesEqual(stderr, {"err"});
+}
diff --git a/adb/types.h b/adb/types.h
index 0090c98..cd1366d 100644
--- a/adb/types.h
+++ b/adb/types.h
@@ -216,7 +216,10 @@
// Add a nonempty block to the chain.
// The end of the chain must be a complete block (i.e. end_offset_ == 0).
void append(std::unique_ptr<const block_type> block) {
- CHECK_NE(0ULL, block->size());
+ if (block->size() == 0) {
+ return;
+ }
+
CHECK_EQ(0ULL, end_offset_);
chain_length_ += block->size();
chain_.emplace_back(std::move(block));
diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp
index 437450c..82ba0a1 100644
--- a/debuggerd/crash_dump.cpp
+++ b/debuggerd/crash_dump.cpp
@@ -48,6 +48,7 @@
#define ATRACE_TAG ATRACE_TAG_BIONIC
#include <utils/Trace.h>
+#include <unwindstack/DexFiles.h>
#include <unwindstack/JitDebug.h>
#include <unwindstack/Maps.h>
#include <unwindstack/Memory.h>
@@ -566,7 +567,7 @@
// TODO: Use seccomp to lock ourselves down.
unwindstack::UnwinderFromPid unwinder(256, vm_pid);
- if (!unwinder.Init()) {
+ if (!unwinder.Init(unwindstack::Regs::CurrentArch())) {
LOG(FATAL) << "Failed to init unwinder object.";
}
diff --git a/debuggerd/handler/debuggerd_fallback.cpp b/debuggerd/handler/debuggerd_fallback.cpp
index 5f7ebc3..bbec612 100644
--- a/debuggerd/handler/debuggerd_fallback.cpp
+++ b/debuggerd/handler/debuggerd_fallback.cpp
@@ -42,6 +42,7 @@
#include <android-base/file.h>
#include <android-base/unique_fd.h>
#include <async_safe/log.h>
+#include <unwindstack/DexFiles.h>
#include <unwindstack/JitDebug.h>
#include <unwindstack/Maps.h>
#include <unwindstack/Memory.h>
@@ -80,12 +81,12 @@
thread.pid = getpid();
thread.tid = gettid();
thread.thread_name = get_thread_name(gettid());
- thread.registers.reset(
- unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), ucontext));
+ unwindstack::ArchEnum arch = unwindstack::Regs::CurrentArch();
+ thread.registers.reset(unwindstack::Regs::CreateFromUcontext(arch, ucontext));
// TODO: Create this once and store it in a global?
unwindstack::UnwinderFromPid unwinder(kMaxFrames, getpid());
- if (unwinder.Init()) {
+ if (unwinder.Init(arch)) {
dump_backtrace_thread(output_fd, &unwinder, thread);
} else {
async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Unable to init unwinder.");
diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
index 7c5304e..238c00c 100644
--- a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
+++ b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h
@@ -18,6 +18,7 @@
#ifndef _DEBUGGERD_UTILITY_H
#define _DEBUGGERD_UTILITY_H
+#include <inttypes.h>
#include <signal.h>
#include <stdbool.h>
#include <sys/types.h>
@@ -25,7 +26,6 @@
#include <string>
#include <android-base/macros.h>
-#include <backtrace/Backtrace.h>
struct log_t {
// Tombstone file descriptor.
@@ -61,6 +61,14 @@
OPEN_FILES
};
+#if defined(__LP64__)
+#define PRIPTR "016" PRIx64
+typedef uint64_t word_t;
+#else
+#define PRIPTR "08" PRIx64
+typedef uint32_t word_t;
+#endif
+
// Log information onto the tombstone.
void _LOG(log_t* log, logtype ltype, const char* fmt, ...) __attribute__((format(printf, 3, 4)));
diff --git a/debuggerd/libdebuggerd/test/tombstone_test.cpp b/debuggerd/libdebuggerd/test/tombstone_test.cpp
index eed5bd3..3196ce8 100644
--- a/debuggerd/libdebuggerd/test/tombstone_test.cpp
+++ b/debuggerd/libdebuggerd/test/tombstone_test.cpp
@@ -15,6 +15,7 @@
*/
#include <stdlib.h>
+#include <sys/mman.h>
#include <time.h>
#include <memory>
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index 4bdb9c8..cc337ed 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -27,6 +27,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/mman.h>
#include <sys/ptrace.h>
#include <sys/stat.h>
#include <time.h>
@@ -44,6 +45,7 @@
#include <log/log.h>
#include <log/logprint.h>
#include <private/android_filesystem_config.h>
+#include <unwindstack/DexFiles.h>
#include <unwindstack/JitDebug.h>
#include <unwindstack/Maps.h>
#include <unwindstack/Memory.h>
@@ -649,7 +651,7 @@
};
unwindstack::UnwinderFromPid unwinder(kMaxFrames, pid);
- if (!unwinder.Init()) {
+ if (!unwinder.Init(unwindstack::Regs::CurrentArch())) {
LOG(FATAL) << "Failed to init unwinder object.";
}
diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp
index d0c5234..7aebea8 100644
--- a/debuggerd/libdebuggerd/utility.cpp
+++ b/debuggerd/libdebuggerd/utility.cpp
@@ -35,7 +35,6 @@
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
-#include <backtrace/Backtrace.h>
#include <debuggerd/handler.h>
#include <log/log.h>
#include <unwindstack/Memory.h>
diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp
index f6f6f50..4043fc6 100644
--- a/fs_mgr/fs_mgr_fstab.cpp
+++ b/fs_mgr/fs_mgr_fstab.cpp
@@ -754,14 +754,15 @@
FstabEntry BuildGsiSystemFstabEntry() {
// .logical_partition_name is required to look up AVB Hashtree descriptors.
- FstabEntry system = {.blk_device = "system_gsi",
- .mount_point = "/system",
- .fs_type = "ext4",
- .flags = MS_RDONLY,
- .fs_options = "barrier=1",
- // could add more keys separated by ':'.
- .avb_keys = "/avb/gsi.avbpubkey:",
- .logical_partition_name = "system"};
+ FstabEntry system = {
+ .blk_device = "system_gsi",
+ .mount_point = "/system",
+ .fs_type = "ext4",
+ .flags = MS_RDONLY,
+ .fs_options = "barrier=1",
+ // could add more keys separated by ':'.
+ .avb_keys = "/avb/q-gsi.avbpubkey:/avb/r-gsi.avbpubkey:/avb/s-gsi.avbpubkey",
+ .logical_partition_name = "system"};
system.fs_mgr_flags.wait = true;
system.fs_mgr_flags.logical = true;
system.fs_mgr_flags.first_stage_mount = true;
diff --git a/fs_mgr/libfiemap_writer/Android.mk b/fs_mgr/libfiemap_writer/Android.mk
new file mode 100644
index 0000000..3c07b8e
--- /dev/null
+++ b/fs_mgr/libfiemap_writer/Android.mk
@@ -0,0 +1,22 @@
+#
+# Copyright (C) 2019 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := VtsFiemapWriterTest
+-include test/vts/tools/build/Android.host_config.mk
diff --git a/fs_mgr/libfiemap_writer/AndroidTest.xml b/fs_mgr/libfiemap_writer/AndroidTest.xml
new file mode 100644
index 0000000..08cff0e
--- /dev/null
+++ b/fs_mgr/libfiemap_writer/AndroidTest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+<configuration description="Config for VTS VtsFiemapWriterTest">
+ <option name="config-descriptor:metadata" key="plan" value="vts-kernel" />
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
+ <option name="abort-on-push-failure" value="false"/>
+ <option name="push-group" value="HostDrivenTest.push"/>
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+ <option name="test-module-name" value="VtsFiemapWriterTest"/>
+ <option name="binary-test-source" value="_32bit::DATA/nativetest/fiemap_writer_test/fiemap_writer_test" />
+ <option name="binary-test-source" value="_64bit::DATA/nativetest64/fiemap_writer_test/fiemap_writer_test" />
+ <option name="binary-test-type" value="gtest"/>
+ <option name="test-timeout" value="1m"/>
+ </test>
+</configuration>
diff --git a/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp b/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp
index ca51689..dda7dfd 100644
--- a/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp
+++ b/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp
@@ -498,17 +498,22 @@
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
- if (argc <= 1) {
- cerr << "Usage: <test_dir> [file_size]\n";
+ if (argc > 1 && argv[1] == "-h"s) {
+ cerr << "Usage: [test_dir] [file_size]\n";
cerr << "\n";
cerr << "Note: test_dir must be a writable, unencrypted directory.\n";
exit(EXIT_FAILURE);
}
::android::base::InitLogging(argv, ::android::base::StderrLogger);
- std::string tempdir = argv[1] + "/XXXXXX"s;
+ std::string root_dir = "/data/local/unencrypted";
+ if (access(root_dir.c_str(), F_OK)) {
+ root_dir = "/data";
+ }
+
+ std::string tempdir = root_dir + "/XXXXXX"s;
if (!mkdtemp(tempdir.data())) {
- cerr << "unable to create tempdir on " << argv[1] << "\n";
+ cerr << "unable to create tempdir on " << root_dir << "\n";
exit(EXIT_FAILURE);
}
if (!android::base::Realpath(tempdir, &gTestDir)) {
diff --git a/fs_mgr/liblp/images.cpp b/fs_mgr/liblp/images.cpp
index 56b5353..db27022 100644
--- a/fs_mgr/liblp/images.cpp
+++ b/fs_mgr/liblp/images.cpp
@@ -98,11 +98,12 @@
return WriteToImageFile(fd, input);
}
-SparseBuilder::SparseBuilder(const LpMetadata& metadata, uint32_t block_size,
- const std::map<std::string, std::string>& images)
+ImageBuilder::ImageBuilder(const LpMetadata& metadata, uint32_t block_size,
+ const std::map<std::string, std::string>& images, bool sparsify)
: metadata_(metadata),
geometry_(metadata.geometry),
block_size_(block_size),
+ sparsify_(sparsify),
images_(images) {
uint64_t total_size = GetTotalSuperPartitionSize(metadata);
if (block_size % LP_SECTOR_SIZE != 0) {
@@ -144,11 +145,11 @@
}
}
-bool SparseBuilder::IsValid() const {
+bool ImageBuilder::IsValid() const {
return device_images_.size() == metadata_.block_devices.size();
}
-bool SparseBuilder::Export(const char* file) {
+bool ImageBuilder::Export(const char* file) {
unique_fd fd(open(file, O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC, 0644));
if (fd < 0) {
PERROR << "open failed: " << file;
@@ -158,8 +159,8 @@
LERROR << "Cannot export to a single image on retrofit builds.";
return false;
}
- // No gzip compression; sparseify; no checksum.
- int ret = sparse_file_write(device_images_[0].get(), fd, false, true, false);
+ // No gzip compression; no checksum.
+ int ret = sparse_file_write(device_images_[0].get(), fd, false, sparsify_, false);
if (ret != 0) {
LERROR << "sparse_file_write failed (error code " << ret << ")";
return false;
@@ -167,7 +168,7 @@
return true;
}
-bool SparseBuilder::ExportFiles(const std::string& output_dir) {
+bool ImageBuilder::ExportFiles(const std::string& output_dir) {
for (size_t i = 0; i < device_images_.size(); i++) {
std::string name = GetBlockDevicePartitionName(metadata_.block_devices[i]);
std::string file_name = "super_" + name + ".img";
@@ -179,8 +180,8 @@
PERROR << "open failed: " << file_path;
return false;
}
- // No gzip compression; sparseify; no checksum.
- int ret = sparse_file_write(device_images_[i].get(), fd, false, true, false);
+ // No gzip compression; no checksum.
+ int ret = sparse_file_write(device_images_[i].get(), fd, false, sparsify_, false);
if (ret != 0) {
LERROR << "sparse_file_write failed (error code " << ret << ")";
return false;
@@ -189,7 +190,7 @@
return true;
}
-bool SparseBuilder::AddData(sparse_file* file, const std::string& blob, uint64_t sector) {
+bool ImageBuilder::AddData(sparse_file* file, const std::string& blob, uint64_t sector) {
uint32_t block;
if (!SectorToBlock(sector, &block)) {
return false;
@@ -203,7 +204,7 @@
return true;
}
-bool SparseBuilder::SectorToBlock(uint64_t sector, uint32_t* block) {
+bool ImageBuilder::SectorToBlock(uint64_t sector, uint32_t* block) {
// The caller must ensure that the metadata has an alignment that is a
// multiple of the block size. liblp will take care of the rest, ensuring
// that all partitions are on an aligned boundary. Therefore all writes
@@ -218,11 +219,11 @@
return true;
}
-uint64_t SparseBuilder::BlockToSector(uint64_t block) const {
+uint64_t ImageBuilder::BlockToSector(uint64_t block) const {
return (block * block_size_) / LP_SECTOR_SIZE;
}
-bool SparseBuilder::Build() {
+bool ImageBuilder::Build() {
if (sparse_file_add_fill(device_images_[0].get(), 0, LP_PARTITION_RESERVED_BYTES, 0) < 0) {
LERROR << "Could not add initial sparse block for reserved zeroes";
return false;
@@ -275,8 +276,8 @@
return true;
}
-bool SparseBuilder::AddPartitionImage(const LpMetadataPartition& partition,
- const std::string& file) {
+bool ImageBuilder::AddPartitionImage(const LpMetadataPartition& partition,
+ const std::string& file) {
// Track which extent we're processing.
uint32_t extent_index = partition.first_extent_index;
@@ -371,7 +372,7 @@
return true;
}
-uint64_t SparseBuilder::ComputePartitionSize(const LpMetadataPartition& partition) const {
+uint64_t ImageBuilder::ComputePartitionSize(const LpMetadataPartition& partition) const {
uint64_t sectors = 0;
for (size_t i = 0; i < partition.num_extents; i++) {
sectors += metadata_.extents[partition.first_extent_index + i].num_sectors;
@@ -386,7 +387,7 @@
//
// Without this, it would be more difficult to find the appropriate extent for
// an output block. With this guarantee it is a linear walk.
-bool SparseBuilder::CheckExtentOrdering() {
+bool ImageBuilder::CheckExtentOrdering() {
std::vector<uint64_t> last_sectors(metadata_.block_devices.size());
for (const auto& extent : metadata_.extents) {
@@ -407,7 +408,7 @@
return true;
}
-int SparseBuilder::OpenImageFile(const std::string& file) {
+int ImageBuilder::OpenImageFile(const std::string& file) {
android::base::unique_fd source_fd = GetControlFileOrOpen(file.c_str(), O_RDONLY | O_CLOEXEC);
if (source_fd < 0) {
PERROR << "open image file failed: " << file;
@@ -437,15 +438,16 @@
return temp_fds_.back().get();
}
-bool WriteToSparseFile(const char* file, const LpMetadata& metadata, uint32_t block_size,
- const std::map<std::string, std::string>& images) {
- SparseBuilder builder(metadata, block_size, images);
+bool WriteToImageFile(const char* file, const LpMetadata& metadata, uint32_t block_size,
+ const std::map<std::string, std::string>& images, bool sparsify) {
+ ImageBuilder builder(metadata, block_size, images, sparsify);
return builder.IsValid() && builder.Build() && builder.Export(file);
}
-bool WriteSplitSparseFiles(const std::string& output_dir, const LpMetadata& metadata,
- uint32_t block_size, const std::map<std::string, std::string>& images) {
- SparseBuilder builder(metadata, block_size, images);
+bool WriteSplitImageFiles(const std::string& output_dir, const LpMetadata& metadata,
+ uint32_t block_size, const std::map<std::string, std::string>& images,
+ bool sparsify) {
+ ImageBuilder builder(metadata, block_size, images, sparsify);
return builder.IsValid() && builder.Build() && builder.ExportFiles(output_dir);
}
diff --git a/fs_mgr/liblp/images.h b/fs_mgr/liblp/images.h
index 44217a0..75060f9 100644
--- a/fs_mgr/liblp/images.h
+++ b/fs_mgr/liblp/images.h
@@ -32,13 +32,13 @@
bool WriteToImageFile(const char* file, const LpMetadata& metadata);
bool WriteToImageFile(int fd, const LpMetadata& metadata);
-// We use an object to build the sparse file since it requires that data
+// We use an object to build the image file since it requires that data
// pointers be held alive until the sparse file is destroyed. It's easier
// to do this when the data pointers are all in one place.
-class SparseBuilder {
+class ImageBuilder {
public:
- SparseBuilder(const LpMetadata& metadata, uint32_t block_size,
- const std::map<std::string, std::string>& images);
+ ImageBuilder(const LpMetadata& metadata, uint32_t block_size,
+ const std::map<std::string, std::string>& images, bool sparsify);
bool Build();
bool Export(const char* file);
@@ -60,6 +60,7 @@
const LpMetadata& metadata_;
const LpMetadataGeometry& geometry_;
uint32_t block_size_;
+ bool sparsify_;
std::vector<SparsePtr> device_images_;
std::string all_metadata_;
diff --git a/fs_mgr/liblp/include/liblp/liblp.h b/fs_mgr/liblp/include/liblp/liblp.h
index 6348f55..5f782b0 100644
--- a/fs_mgr/liblp/include/liblp/liblp.h
+++ b/fs_mgr/liblp/include/liblp/liblp.h
@@ -72,8 +72,8 @@
// Read/Write logical partition metadata to an image file, for diagnostics or
// flashing.
-bool WriteToSparseFile(const char* file, const LpMetadata& metadata, uint32_t block_size,
- const std::map<std::string, std::string>& images);
+bool WriteToImageFile(const char* file, const LpMetadata& metadata, uint32_t block_size,
+ const std::map<std::string, std::string>& images, bool sparsify);
bool WriteToImageFile(const char* file, const LpMetadata& metadata);
std::unique_ptr<LpMetadata> ReadFromImageFile(const std::string& image_file);
std::unique_ptr<LpMetadata> ReadFromImageBlob(const void* data, size_t bytes);
@@ -83,8 +83,9 @@
// is intended for retrofit devices, and will generate one sparse file per
// block device (each named super_<name>.img) and placed in the specified
// output folder.
-bool WriteSplitSparseFiles(const std::string& output_dir, const LpMetadata& metadata,
- uint32_t block_size, const std::map<std::string, std::string>& images);
+bool WriteSplitImageFiles(const std::string& output_dir, const LpMetadata& metadata,
+ uint32_t block_size, const std::map<std::string, std::string>& images,
+ bool sparsify);
// Helper to extract safe C++ strings from partition info.
std::string GetPartitionName(const LpMetadataPartition& partition);
diff --git a/fs_mgr/liblp/io_test.cpp b/fs_mgr/liblp/io_test.cpp
index 9f3314d..8fc02cb 100644
--- a/fs_mgr/liblp/io_test.cpp
+++ b/fs_mgr/liblp/io_test.cpp
@@ -598,7 +598,7 @@
ASSERT_NE(exported, nullptr);
// Build the sparse file.
- SparseBuilder sparse(*exported.get(), 512, {});
+ ImageBuilder sparse(*exported.get(), 512, {}, true /* sparsify */);
ASSERT_TRUE(sparse.IsValid());
ASSERT_TRUE(sparse.Build());
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index d458924..3900f72 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -80,7 +80,7 @@
bool InitMappedDevice(const std::string& verity_device);
bool InitDeviceMapper();
bool CreateLogicalPartitions();
- bool MountPartition(const Fstab::iterator& begin, bool erase_used_fstab_entry,
+ bool MountPartition(const Fstab::iterator& begin, bool erase_same_mounts,
Fstab::iterator* end = nullptr);
bool MountPartitions();
@@ -437,21 +437,26 @@
uevent_listener_.RegenerateUeventsForPath(syspath, verity_callback);
if (!found) {
- LOG(INFO) << "dm-verity device not found in /sys, waiting for its uevent";
+ LOG(INFO) << "dm device '" << dm_device << "' not found in /sys, waiting for its uevent";
Timer t;
uevent_listener_.Poll(verity_callback, 10s);
- LOG(INFO) << "wait for dm-verity device returned after " << t;
+ LOG(INFO) << "wait for dm device '" << dm_device << "' returned after " << t;
}
if (!found) {
- LOG(ERROR) << "dm-verity device not found after polling timeout";
+ LOG(ERROR) << "dm device '" << dm_device << "' not found after polling timeout";
return false;
}
return true;
}
-bool FirstStageMount::MountPartition(const Fstab::iterator& begin, bool erase_used_fstab_entry,
+bool FirstStageMount::MountPartition(const Fstab::iterator& begin, bool erase_same_mounts,
Fstab::iterator* end) {
+ // Sets end to begin + 1, so we can just return on failure below.
+ if (end) {
+ *end = begin + 1;
+ }
+
if (begin->fs_mgr_flags.logical) {
if (!fs_mgr_update_logical_partition(&(*begin))) {
return false;
@@ -477,7 +482,7 @@
mounted = (fs_mgr_do_mount_one(*current) == 0);
}
}
- if (erase_used_fstab_entry) {
+ if (erase_same_mounts) {
current = fstab_.erase(begin, current);
}
if (end) {
@@ -494,7 +499,7 @@
return entry.mount_point == "/metadata";
});
if (metadata_partition != fstab_.end()) {
- if (MountPartition(metadata_partition, true /* erase_used_fstab_entry */)) {
+ if (MountPartition(metadata_partition, true /* erase_same_mounts */)) {
UseGsiIfPresent();
}
}
@@ -505,7 +510,7 @@
if (system_partition == fstab_.end()) return true;
- if (MountPartition(system_partition, false)) {
+ if (MountPartition(system_partition, false /* erase_same_mounts */)) {
if (gsi_not_on_userdata_ && fs_mgr_verity_is_check_at_most_once(*system_partition)) {
LOG(ERROR) << "check_most_at_once forbidden on external media";
return false;
@@ -560,7 +565,7 @@
}
Fstab::iterator end;
- if (!MountPartition(current, false, &end)) {
+ if (!MountPartition(current, false /* erase_same_mounts */, &end)) {
if (current->fs_mgr_flags.no_fail) {
LOG(INFO) << "Failed to mount " << current->mount_point
<< ", ignoring mount for no_fail partition";
@@ -797,11 +802,9 @@
bool FirstStageMountVBootV2::SetUpDmVerity(FstabEntry* fstab_entry) {
AvbHashtreeResult hashtree_result;
- if (fstab_entry->fs_mgr_flags.avb) {
- if (!InitAvbHandle()) return false;
- hashtree_result =
- avb_handle_->SetUpAvbHashtree(fstab_entry, false /* wait_for_verity_dev */);
- } else if (!fstab_entry->avb_keys.empty()) {
+ // It's possible for a fstab_entry to have both avb_keys and avb flag.
+ // In this case, try avb_keys first, then fallback to avb flag.
+ if (!fstab_entry->avb_keys.empty()) {
if (!InitAvbHandle()) return false;
// Checks if hashtree should be disabled from the top-level /vbmeta.
if (avb_handle_->status() == AvbHandleStatus::kHashtreeDisabled ||
@@ -813,14 +816,24 @@
auto avb_standalone_handle = AvbHandle::LoadAndVerifyVbmeta(*fstab_entry);
if (!avb_standalone_handle) {
LOG(ERROR) << "Failed to load offline vbmeta for " << fstab_entry->mount_point;
- return false;
+ // Fallbacks to built-in hashtree if fs_mgr_flags.avb is set.
+ if (!fstab_entry->fs_mgr_flags.avb) return false;
+ LOG(INFO) << "Fallback to built-in hashtree for " << fstab_entry->mount_point;
+ hashtree_result =
+ avb_handle_->SetUpAvbHashtree(fstab_entry, false /* wait_for_verity_dev */);
+ } else {
+ // Sets up hashtree via the standalone handle.
+ if (IsStandaloneImageRollback(*avb_handle_, *avb_standalone_handle, *fstab_entry)) {
+ return false;
+ }
+ hashtree_result = avb_standalone_handle->SetUpAvbHashtree(
+ fstab_entry, false /* wait_for_verity_dev */);
}
- if (IsStandaloneImageRollback(*avb_handle_, *avb_standalone_handle, *fstab_entry)) {
- return false;
- }
- hashtree_result = avb_standalone_handle->SetUpAvbHashtree(
- fstab_entry, false /* wait_for_verity_dev */);
}
+ } else if (fstab_entry->fs_mgr_flags.avb) {
+ if (!InitAvbHandle()) return false;
+ hashtree_result =
+ avb_handle_->SetUpAvbHashtree(fstab_entry, false /* wait_for_verity_dev */);
} else {
return true; // No need AVB, returns true to mount the partition directly.
}
diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp
index ff19833..f5f9b2a 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -32,6 +32,9 @@
#include <unwindstack/Regs.h>
#include <unwindstack/RegsGetLocal.h>
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+#include <unwindstack/DexFiles.h>
+#endif
#include <unwindstack/Unwinder.h>
#include "BacktraceLog.h"
@@ -47,6 +50,14 @@
regs, stack_map->process_memory());
unwinder.SetResolveNames(stack_map->ResolveNames());
stack_map->SetArch(regs->Arch());
+ if (stack_map->GetJitDebug() != nullptr) {
+ unwinder.SetJitDebug(stack_map->GetJitDebug(), regs->Arch());
+ }
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+ if (stack_map->GetDexFiles() != nullptr) {
+ unwinder.SetDexFiles(stack_map->GetDexFiles(), regs->Arch());
+ }
+#endif
unwinder.Unwind(skip_names, &stack_map->GetSuffixesToIgnore());
if (error != nullptr) {
switch (unwinder.LastErrorCode()) {
diff --git a/libbacktrace/UnwindStackMap.cpp b/libbacktrace/UnwindStackMap.cpp
index 726fdfa..4518891 100644
--- a/libbacktrace/UnwindStackMap.cpp
+++ b/libbacktrace/UnwindStackMap.cpp
@@ -43,6 +43,13 @@
// Create the process memory object.
process_memory_ = unwindstack::Memory::CreateProcessMemory(pid_);
+ // Create a JitDebug object for getting jit unwind information.
+ std::vector<std::string> search_libs_{"libart.so", "libartd.so"};
+ jit_debug_.reset(new unwindstack::JitDebug(process_memory_, search_libs_));
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+ dex_files_.reset(new unwindstack::DexFiles(process_memory_, search_libs_));
+#endif
+
if (!stack_maps_->Parse()) {
return false;
}
diff --git a/libbacktrace/UnwindStackMap.h b/libbacktrace/UnwindStackMap.h
index 9bb9709..e19b605 100644
--- a/libbacktrace/UnwindStackMap.h
+++ b/libbacktrace/UnwindStackMap.h
@@ -27,6 +27,9 @@
#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+#include <unwindstack/DexFiles.h>
+#endif
#include <unwindstack/Elf.h>
#include <unwindstack/JitDebug.h>
#include <unwindstack/Maps.h>
@@ -50,6 +53,12 @@
const std::shared_ptr<unwindstack::Memory>& process_memory() { return process_memory_; }
+ unwindstack::JitDebug* GetJitDebug() { return jit_debug_.get(); }
+
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+ unwindstack::DexFiles* GetDexFiles() { return dex_files_.get(); }
+#endif
+
void SetArch(unwindstack::ArchEnum arch) { arch_ = arch; }
protected:
@@ -57,6 +66,11 @@
std::unique_ptr<unwindstack::Maps> stack_maps_;
std::shared_ptr<unwindstack::Memory> process_memory_;
+ std::unique_ptr<unwindstack::JitDebug> jit_debug_;
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+ std::unique_ptr<unwindstack::DexFiles> dex_files_;
+#endif
+
unwindstack::ArchEnum arch_ = unwindstack::ARCH_UNKNOWN;
};
diff --git a/libcutils/ashmem-dev.cpp b/libcutils/ashmem-dev.cpp
index e35b91a..e67b458 100644
--- a/libcutils/ashmem-dev.cpp
+++ b/libcutils/ashmem-dev.cpp
@@ -73,6 +73,8 @@
#ifndef __ANDROID_VNDK__
using openFdType = int (*)();
+static openFdType openFd;
+
openFdType initOpenAshmemFd() {
openFdType openFd = nullptr;
void* handle = dlopen("libashmemd_client.so", RTLD_NOW);
@@ -221,7 +223,10 @@
int fd = -1;
#ifndef __ANDROID_VNDK__
- static auto openFd = initOpenAshmemFd();
+ if (!openFd) {
+ openFd = initOpenAshmemFd();
+ }
+
if (openFd) {
fd = openFd();
}
@@ -480,3 +485,11 @@
return __ashmem_check_failure(fd, TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_GET_SIZE, NULL)));
}
+
+void ashmem_init() {
+#ifndef __ANDROID_VNDK__
+ pthread_mutex_lock(&__ashmem_lock);
+ openFd = initOpenAshmemFd();
+ pthread_mutex_unlock(&__ashmem_lock);
+#endif //__ANDROID_VNDK__
+}
diff --git a/libcutils/ashmem-host.cpp b/libcutils/ashmem-host.cpp
index bb990d5..32446d4 100644
--- a/libcutils/ashmem-host.cpp
+++ b/libcutils/ashmem-host.cpp
@@ -82,3 +82,5 @@
return buf.st_size;
}
+
+void ashmem_init() {}
diff --git a/libcutils/include/cutils/ashmem.h b/libcutils/include/cutils/ashmem.h
index d80caa6..abc5068 100644
--- a/libcutils/include/cutils/ashmem.h
+++ b/libcutils/include/cutils/ashmem.h
@@ -26,6 +26,7 @@
int ashmem_pin_region(int fd, size_t offset, size_t len);
int ashmem_unpin_region(int fd, size_t offset, size_t len);
int ashmem_get_size_region(int fd);
+void ashmem_init();
#ifdef __cplusplus
}
diff --git a/libmeminfo/tools/procrank.cpp b/libmeminfo/tools/procrank.cpp
index 21a684c..5e89254 100644
--- a/libmeminfo/tools/procrank.cpp
+++ b/libmeminfo/tools/procrank.cpp
@@ -14,11 +14,17 @@
* limitations under the License.
*/
+#include <android-base/file.h>
+#include <android-base/parseint.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <dirent.h>
#include <errno.h>
#include <inttypes.h>
#include <linux/kernel-page-flags.h>
#include <linux/oom.h>
+#include <meminfo/procmeminfo.h>
+#include <meminfo/sysmeminfo.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
@@ -29,14 +35,6 @@
#include <sstream>
#include <vector>
-#include <android-base/file.h>
-#include <android-base/parseint.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-
-#include <meminfo/procmeminfo.h>
-#include <meminfo/sysmeminfo.h>
-
using ::android::meminfo::MemUsage;
using ::android::meminfo::ProcMemInfo;
@@ -460,8 +458,16 @@
auto mark_swap_usage = [&](pid_t pid) -> bool {
ProcessRecord proc(pid, show_wss, pgflags, pgflags_mask);
if (!proc.valid()) {
- std::cerr << "Failed to create process record for: " << pid << std::endl;
- return false;
+ // Check to see if the process is still around, skip the process if the proc
+ // directory is inaccessible. It was most likely killed while creating the process
+ // record
+ std::string procdir = ::android::base::StringPrintf("/proc/%d", pid);
+ if (access(procdir.c_str(), F_OK | R_OK)) return true;
+
+ // Warn if we failed to gather process stats even while it is still alive.
+ // Return success here, so we continue to print stats for other processes.
+ std::cerr << "warning: failed to create process record for: " << pid << std::endl;
+ return true;
}
// Skip processes with no memory mappings
@@ -479,9 +485,9 @@
return true;
};
- // Get a list of all pids currently running in the system in
- // 1st pass through all processes. Mark each swap offset used by the process as we find them
- // for calculating proportional swap usage later.
+ // Get a list of all pids currently running in the system in 1st pass through all processes.
+ // Mark each swap offset used by the process as we find them for calculating proportional
+ // swap usage later.
if (!read_all_pids(&pids, mark_swap_usage)) {
std::cerr << "Failed to read all pids from the system" << std::endl;
exit(EXIT_FAILURE);
diff --git a/libprocessgroup/cgrouprc/Android.bp b/libprocessgroup/cgrouprc/Android.bp
index 774738d..6848620 100644
--- a/libprocessgroup/cgrouprc/Android.bp
+++ b/libprocessgroup/cgrouprc/Android.bp
@@ -45,7 +45,11 @@
symbol_file: "libcgrouprc.map.txt",
versions: ["29"],
},
- version_script: "libcgrouprc.map.txt",
+ target: {
+ linux: {
+ version_script: "libcgrouprc.map.txt",
+ },
+ },
}
llndk_library {
diff --git a/libprocessgroup/setup/cgroup_map_write.cpp b/libprocessgroup/setup/cgroup_map_write.cpp
index 26703ee..da60948 100644
--- a/libprocessgroup/setup/cgroup_map_write.cpp
+++ b/libprocessgroup/setup/cgroup_map_write.cpp
@@ -235,14 +235,9 @@
#endif
-// WARNING: This function should be called only from SetupCgroups and only once.
-// It intentionally leaks an FD, so additional invocation will result in additional leak.
static bool WriteRcFile(const std::map<std::string, CgroupDescriptor>& descriptors) {
- // WARNING: We are intentionally leaking the FD to keep the file open forever.
- // Let init keep the FD open to prevent file mappings from becoming invalid in
- // case the file gets deleted somehow.
- int fd = TEMP_FAILURE_RETRY(open(CGROUPS_RC_PATH, O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC,
- S_IRUSR | S_IRGRP | S_IROTH));
+ unique_fd fd(TEMP_FAILURE_RETRY(open(CGROUPS_RC_PATH, O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC,
+ S_IRUSR | S_IRGRP | S_IROTH)));
if (fd < 0) {
PLOG(ERROR) << "open() failed for " << CGROUPS_RC_PATH;
return false;
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index ce25108..b7650a1 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -49,6 +49,7 @@
srcs: [
"ArmExidx.cpp",
"DexFile.cpp",
+ "DexFiles.cpp",
"DwarfCfa.cpp",
"DwarfEhFrameWithHdr.cpp",
"DwarfMemory.cpp",
@@ -91,6 +92,7 @@
cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
exclude_srcs: [
"DexFile.cpp",
+ "DexFiles.cpp",
],
exclude_shared_libs: [
"libdexfile_support",
@@ -100,6 +102,7 @@
cflags: ["-DNO_LIBDEXFILE_SUPPORT"],
exclude_srcs: [
"DexFile.cpp",
+ "DexFiles.cpp",
],
exclude_shared_libs: [
"libdexfile_support",
diff --git a/libunwindstack/DexFile.cpp b/libunwindstack/DexFile.cpp
index d8d5a24..eaf867f 100644
--- a/libunwindstack/DexFile.cpp
+++ b/libunwindstack/DexFile.cpp
@@ -35,31 +35,22 @@
std::unique_ptr<DexFile> DexFile::Create(uint64_t dex_file_offset_in_memory, Memory* memory,
MapInfo* info) {
if (!info->name.empty()) {
- std::unique_ptr<DexFile> dex_file_from_file =
+ std::unique_ptr<DexFile> dex_file =
DexFileFromFile::Create(dex_file_offset_in_memory - info->start + info->offset, info->name);
- if (dex_file_from_file) {
- dex_file_from_file->addr_ = dex_file_offset_in_memory;
- return dex_file_from_file;
+ if (dex_file) {
+ return dex_file;
}
}
- std::unique_ptr<DexFile> dex_file_from_memory =
- DexFileFromMemory::Create(dex_file_offset_in_memory, memory, info->name);
- if (dex_file_from_memory) {
- dex_file_from_memory->addr_ = dex_file_offset_in_memory;
- return dex_file_from_memory;
- }
- return nullptr;
+ return DexFileFromMemory::Create(dex_file_offset_in_memory, memory, info->name);
}
-bool DexFile::GetFunctionName(uint64_t dex_pc, std::string* method_name, uint64_t* method_offset) {
- uint64_t dex_offset = dex_pc - addr_;
+bool DexFile::GetMethodInformation(uint64_t dex_offset, std::string* method_name,
+ uint64_t* method_offset) {
art_api::dex::MethodInfo method_info = GetMethodInfoForOffset(dex_offset, false);
if (method_info.offset == 0) {
return false;
}
- if (method_name != nullptr) {
- *method_name = method_info.name;
- }
+ *method_name = method_info.name;
*method_offset = dex_offset - method_info.offset;
return true;
}
diff --git a/libunwindstack/DexFile.h b/libunwindstack/DexFile.h
index 1448a4b..ca658e6 100644
--- a/libunwindstack/DexFile.h
+++ b/libunwindstack/DexFile.h
@@ -29,22 +29,17 @@
namespace unwindstack {
-class Memory;
-struct MapInfo;
-
class DexFile : protected art_api::dex::DexFile {
public:
virtual ~DexFile() = default;
- bool GetFunctionName(uint64_t dex_pc, std::string* method_name, uint64_t* method_offset);
+ bool GetMethodInformation(uint64_t dex_offset, std::string* method_name, uint64_t* method_offset);
static std::unique_ptr<DexFile> Create(uint64_t dex_file_offset_in_memory, Memory* memory,
MapInfo* info);
protected:
DexFile(art_api::dex::DexFile&& art_dex_file) : art_api::dex::DexFile(std::move(art_dex_file)) {}
-
- uint64_t addr_ = 0;
};
class DexFileFromFile : public DexFile {
diff --git a/libunwindstack/DexFiles.cpp b/libunwindstack/DexFiles.cpp
new file mode 100644
index 0000000..63a77e5
--- /dev/null
+++ b/libunwindstack/DexFiles.cpp
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2018 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 <stdint.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <memory>
+
+#include <unwindstack/DexFiles.h>
+#include <unwindstack/MapInfo.h>
+#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
+
+#include "DexFile.h"
+
+namespace unwindstack {
+
+struct DEXFileEntry32 {
+ uint32_t next;
+ uint32_t prev;
+ uint32_t dex_file;
+};
+
+struct DEXFileEntry64 {
+ uint64_t next;
+ uint64_t prev;
+ uint64_t dex_file;
+};
+
+DexFiles::DexFiles(std::shared_ptr<Memory>& memory) : Global(memory) {}
+
+DexFiles::DexFiles(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs)
+ : Global(memory, search_libs) {}
+
+DexFiles::~DexFiles() {}
+
+void DexFiles::ProcessArch() {
+ switch (arch()) {
+ case ARCH_ARM:
+ case ARCH_MIPS:
+ case ARCH_X86:
+ read_entry_ptr_func_ = &DexFiles::ReadEntryPtr32;
+ read_entry_func_ = &DexFiles::ReadEntry32;
+ break;
+
+ case ARCH_ARM64:
+ case ARCH_MIPS64:
+ case ARCH_X86_64:
+ read_entry_ptr_func_ = &DexFiles::ReadEntryPtr64;
+ read_entry_func_ = &DexFiles::ReadEntry64;
+ break;
+
+ case ARCH_UNKNOWN:
+ abort();
+ }
+}
+
+uint64_t DexFiles::ReadEntryPtr32(uint64_t addr) {
+ uint32_t entry;
+ const uint32_t field_offset = 12; // offset of first_entry_ in the descriptor struct.
+ if (!memory_->ReadFully(addr + field_offset, &entry, sizeof(entry))) {
+ return 0;
+ }
+ return entry;
+}
+
+uint64_t DexFiles::ReadEntryPtr64(uint64_t addr) {
+ uint64_t entry;
+ const uint32_t field_offset = 16; // offset of first_entry_ in the descriptor struct.
+ if (!memory_->ReadFully(addr + field_offset, &entry, sizeof(entry))) {
+ return 0;
+ }
+ return entry;
+}
+
+bool DexFiles::ReadEntry32() {
+ DEXFileEntry32 entry;
+ if (!memory_->ReadFully(entry_addr_, &entry, sizeof(entry)) || entry.dex_file == 0) {
+ entry_addr_ = 0;
+ return false;
+ }
+
+ addrs_.push_back(entry.dex_file);
+ entry_addr_ = entry.next;
+ return true;
+}
+
+bool DexFiles::ReadEntry64() {
+ DEXFileEntry64 entry;
+ if (!memory_->ReadFully(entry_addr_, &entry, sizeof(entry)) || entry.dex_file == 0) {
+ entry_addr_ = 0;
+ return false;
+ }
+
+ addrs_.push_back(entry.dex_file);
+ entry_addr_ = entry.next;
+ return true;
+}
+
+bool DexFiles::ReadVariableData(uint64_t ptr_offset) {
+ entry_addr_ = (this->*read_entry_ptr_func_)(ptr_offset);
+ return entry_addr_ != 0;
+}
+
+void DexFiles::Init(Maps* maps) {
+ if (initialized_) {
+ return;
+ }
+ initialized_ = true;
+ entry_addr_ = 0;
+
+ FindAndReadVariable(maps, "__dex_debug_descriptor");
+}
+
+DexFile* DexFiles::GetDexFile(uint64_t dex_file_offset, MapInfo* info) {
+ // Lock while processing the data.
+ DexFile* dex_file;
+ auto entry = files_.find(dex_file_offset);
+ if (entry == files_.end()) {
+ std::unique_ptr<DexFile> new_dex_file = DexFile::Create(dex_file_offset, memory_.get(), info);
+ dex_file = new_dex_file.get();
+ files_[dex_file_offset] = std::move(new_dex_file);
+ } else {
+ dex_file = entry->second.get();
+ }
+ return dex_file;
+}
+
+bool DexFiles::GetAddr(size_t index, uint64_t* addr) {
+ if (index < addrs_.size()) {
+ *addr = addrs_[index];
+ return true;
+ }
+ if (entry_addr_ != 0 && (this->*read_entry_func_)()) {
+ *addr = addrs_.back();
+ return true;
+ }
+ return false;
+}
+
+void DexFiles::GetMethodInformation(Maps* maps, MapInfo* info, uint64_t dex_pc,
+ std::string* method_name, uint64_t* method_offset) {
+ std::lock_guard<std::mutex> guard(lock_);
+ if (!initialized_) {
+ Init(maps);
+ }
+
+ size_t index = 0;
+ uint64_t addr;
+ while (GetAddr(index++, &addr)) {
+ if (addr < info->start || addr >= info->end) {
+ continue;
+ }
+
+ DexFile* dex_file = GetDexFile(addr, info);
+ if (dex_file != nullptr &&
+ dex_file->GetMethodInformation(dex_pc - addr, method_name, method_offset)) {
+ break;
+ }
+ }
+}
+
+} // namespace unwindstack
diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp
index 5b402ed..4b93abb 100644
--- a/libunwindstack/Elf.cpp
+++ b/libunwindstack/Elf.cpp
@@ -243,24 +243,6 @@
return false;
}
-bool Elf::GetTextRange(uint64_t* addr, uint64_t* size) {
- if (!valid_) {
- return false;
- }
-
- if (interface_->GetTextRange(addr, size)) {
- *addr += load_bias_;
- return true;
- }
-
- if (gnu_debugdata_interface_ != nullptr && gnu_debugdata_interface_->GetTextRange(addr, size)) {
- *addr += load_bias_;
- return true;
- }
-
- return false;
-}
-
ElfInterface* Elf::CreateInterfaceFromMemory(Memory* memory) {
if (!IsValidElf(memory)) {
return nullptr;
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index e09a2ae..dee8eb3 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -69,15 +69,6 @@
return false;
}
-bool ElfInterface::GetTextRange(uint64_t* addr, uint64_t* size) {
- if (text_size_ != 0) {
- *addr = text_addr_;
- *size = text_size_;
- return true;
- }
- return false;
-}
-
Memory* ElfInterface::CreateGnuDebugdataMemory() {
if (gnu_debugdata_offset_ == 0 || gnu_debugdata_size_ == 0) {
return nullptr;
@@ -285,7 +276,7 @@
if (gnu_build_id_size_ - offset < hdr.n_descsz || hdr.n_descsz == 0) {
return "";
}
- std::string build_id(hdr.n_descsz - 1, '\0');
+ std::string build_id(hdr.n_descsz, '\0');
if (memory_->ReadFully(gnu_build_id_offset_ + offset, &build_id[0], hdr.n_descsz)) {
return build_id;
}
@@ -339,26 +330,29 @@
}
symbols_.push_back(new Symbols(shdr.sh_offset, shdr.sh_size, shdr.sh_entsize,
str_shdr.sh_offset, str_shdr.sh_size));
- } else if (shdr.sh_type == SHT_PROGBITS || shdr.sh_type == SHT_NOBITS) {
+ } else if (shdr.sh_type == SHT_PROGBITS && sec_size != 0) {
// Look for the .debug_frame and .gnu_debugdata.
if (shdr.sh_name < sec_size) {
std::string name;
if (memory_->ReadString(sec_offset + shdr.sh_name, &name)) {
+ uint64_t* offset_ptr = nullptr;
+ uint64_t* size_ptr = nullptr;
if (name == ".debug_frame") {
- debug_frame_offset_ = shdr.sh_offset;
- debug_frame_size_ = shdr.sh_size;
+ offset_ptr = &debug_frame_offset_;
+ size_ptr = &debug_frame_size_;
} else if (name == ".gnu_debugdata") {
- gnu_debugdata_offset_ = shdr.sh_offset;
- gnu_debugdata_size_ = shdr.sh_size;
+ offset_ptr = &gnu_debugdata_offset_;
+ size_ptr = &gnu_debugdata_size_;
} else if (name == ".eh_frame") {
- eh_frame_offset_ = shdr.sh_offset;
- eh_frame_size_ = shdr.sh_size;
+ offset_ptr = &eh_frame_offset_;
+ size_ptr = &eh_frame_size_;
} else if (eh_frame_hdr_offset_ == 0 && name == ".eh_frame_hdr") {
- eh_frame_hdr_offset_ = shdr.sh_offset;
- eh_frame_hdr_size_ = shdr.sh_size;
- } else if (name == ".text") {
- text_addr_ = shdr.sh_addr;
- text_size_ = shdr.sh_size;
+ offset_ptr = &eh_frame_hdr_offset_;
+ size_ptr = &eh_frame_hdr_size_;
+ }
+ if (offset_ptr != nullptr) {
+ *offset_ptr = shdr.sh_offset;
+ *size_ptr = shdr.sh_size;
}
}
}
diff --git a/libunwindstack/JitDebug.cpp b/libunwindstack/JitDebug.cpp
index 71665a1..20bc4b9 100644
--- a/libunwindstack/JitDebug.cpp
+++ b/libunwindstack/JitDebug.cpp
@@ -16,13 +16,8 @@
#include <stdint.h>
#include <sys/mman.h>
-#include <cstddef>
-#include <atomic>
-#include <deque>
-#include <map>
#include <memory>
-#include <unordered_set>
#include <vector>
#include <unwindstack/Elf.h>
@@ -30,334 +25,197 @@
#include <unwindstack/Maps.h>
#include <unwindstack/Memory.h>
-#if !defined(NO_LIBDEXFILE_SUPPORT)
-#include <DexFile.h>
-#endif
-
// This implements the JIT Compilation Interface.
// See https://sourceware.org/gdb/onlinedocs/gdb/JIT-Interface.html
namespace unwindstack {
-// 32-bit platforms may differ in alignment of uint64_t.
-struct Uint64_P {
- uint64_t value;
+struct JITCodeEntry32Pack {
+ uint32_t next;
+ uint32_t prev;
+ uint32_t symfile_addr;
+ uint64_t symfile_size;
} __attribute__((packed));
-struct Uint64_A {
- uint64_t value;
-} __attribute__((aligned(8)));
-// Wrapper around other memory object which protects us against data races.
-// It will check seqlock after every read, and fail if the seqlock changed.
-// This ensues that the read memory has not been partially modified.
-struct JitMemory : public Memory {
- size_t Read(uint64_t addr, void* dst, size_t size) override;
-
- Memory* parent_ = nullptr;
- uint64_t seqlock_addr_ = 0;
- uint32_t expected_seqlock_ = 0;
- bool failed_due_to_race_ = false;
+struct JITCodeEntry32Pad {
+ uint32_t next;
+ uint32_t prev;
+ uint32_t symfile_addr;
+ uint32_t pad;
+ uint64_t symfile_size;
};
-template <typename Symfile>
-struct JitCacheEntry {
- // PC memory range described by this entry.
- uint64_t addr_ = 0;
- uint64_t size_ = 0;
- std::unique_ptr<Symfile> symfile_;
-
- bool Init(Maps* maps, JitMemory* memory, uint64_t addr, uint64_t size);
+struct JITCodeEntry64 {
+ uint64_t next;
+ uint64_t prev;
+ uint64_t symfile_addr;
+ uint64_t symfile_size;
};
-template <typename Symfile, typename PointerT, typename Uint64_T>
-class JitDebugImpl : public JitDebug<Symfile>, public Global {
- public:
- static constexpr const char* kDescriptorExtMagic = "Android1";
- static constexpr int kMaxRaceRetries = 16;
+struct JITDescriptorHeader {
+ uint32_t version;
+ uint32_t action_flag;
+};
- struct JITCodeEntry {
- PointerT next;
- PointerT prev;
- PointerT symfile_addr;
- Uint64_T symfile_size;
- };
+struct JITDescriptor32 {
+ JITDescriptorHeader header;
+ uint32_t relevant_entry;
+ uint32_t first_entry;
+};
- struct JITDescriptor {
- uint32_t version;
- uint32_t action_flag;
- PointerT relevant_entry;
- PointerT first_entry;
- };
+struct JITDescriptor64 {
+ JITDescriptorHeader header;
+ uint64_t relevant_entry;
+ uint64_t first_entry;
+};
- // Android-specific extensions.
- struct JITDescriptorExt {
- JITDescriptor desc;
- uint8_t magic[8];
- uint32_t flags;
- uint32_t sizeof_descriptor;
- uint32_t sizeof_entry;
- uint32_t action_seqlock;
- uint64_t action_timestamp;
- };
+JitDebug::JitDebug(std::shared_ptr<Memory>& memory) : Global(memory) {}
- JitDebugImpl(ArchEnum arch, std::shared_ptr<Memory>& memory,
- std::vector<std::string>& search_libs)
- : Global(memory, search_libs) {
- SetArch(arch);
+JitDebug::JitDebug(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs)
+ : Global(memory, search_libs) {}
+
+JitDebug::~JitDebug() {
+ for (auto* elf : elf_list_) {
+ delete elf;
+ }
+}
+
+uint64_t JitDebug::ReadDescriptor32(uint64_t addr) {
+ JITDescriptor32 desc;
+ if (!memory_->ReadFully(addr, &desc, sizeof(desc))) {
+ return 0;
}
- Symfile* Get(Maps* maps, uint64_t pc) override;
- virtual bool ReadVariableData(uint64_t offset);
- virtual void ProcessArch() {}
- bool Update(Maps* maps);
- bool Read(Maps* maps, JitMemory* memory);
+ if (desc.header.version != 1 || desc.first_entry == 0) {
+ // Either unknown version, or no jit entries.
+ return 0;
+ }
- bool initialized_ = false;
- uint64_t descriptor_addr_ = 0; // Non-zero if we have found (non-empty) descriptor.
- uint64_t seqlock_addr_ = 0; // Re-read entries if the value at this address changes.
- uint32_t last_seqlock_ = ~0u; // The value of seqlock when we last read the entries.
+ return desc.first_entry;
+}
- std::deque<JitCacheEntry<Symfile>> entries_;
+uint64_t JitDebug::ReadDescriptor64(uint64_t addr) {
+ JITDescriptor64 desc;
+ if (!memory_->ReadFully(addr, &desc, sizeof(desc))) {
+ return 0;
+ }
- std::mutex lock_;
-};
+ if (desc.header.version != 1 || desc.first_entry == 0) {
+ // Either unknown version, or no jit entries.
+ return 0;
+ }
-template <typename Symfile>
-std::unique_ptr<JitDebug<Symfile>> JitDebug<Symfile>::Create(ArchEnum arch,
- std::shared_ptr<Memory>& memory,
- std::vector<std::string> search_libs) {
- typedef JitDebugImpl<Symfile, uint32_t, Uint64_P> JitDebugImpl32P;
- typedef JitDebugImpl<Symfile, uint32_t, Uint64_A> JitDebugImpl32A;
- typedef JitDebugImpl<Symfile, uint64_t, Uint64_A> JitDebugImpl64A;
- switch (arch) {
+ return desc.first_entry;
+}
+
+uint64_t JitDebug::ReadEntry32Pack(uint64_t* start, uint64_t* size) {
+ JITCodeEntry32Pack code;
+ if (!memory_->ReadFully(entry_addr_, &code, sizeof(code))) {
+ return 0;
+ }
+
+ *start = code.symfile_addr;
+ *size = code.symfile_size;
+ return code.next;
+}
+
+uint64_t JitDebug::ReadEntry32Pad(uint64_t* start, uint64_t* size) {
+ JITCodeEntry32Pad code;
+ if (!memory_->ReadFully(entry_addr_, &code, sizeof(code))) {
+ return 0;
+ }
+
+ *start = code.symfile_addr;
+ *size = code.symfile_size;
+ return code.next;
+}
+
+uint64_t JitDebug::ReadEntry64(uint64_t* start, uint64_t* size) {
+ JITCodeEntry64 code;
+ if (!memory_->ReadFully(entry_addr_, &code, sizeof(code))) {
+ return 0;
+ }
+
+ *start = code.symfile_addr;
+ *size = code.symfile_size;
+ return code.next;
+}
+
+void JitDebug::ProcessArch() {
+ switch (arch()) {
case ARCH_X86:
- static_assert(sizeof(typename JitDebugImpl32P::JITCodeEntry) == 20, "layout");
- static_assert(sizeof(typename JitDebugImpl32P::JITDescriptor) == 16, "layout");
- static_assert(sizeof(typename JitDebugImpl32P::JITDescriptorExt) == 48, "layout");
- return std::unique_ptr<JitDebug>(new JitDebugImpl32P(arch, memory, search_libs));
+ read_descriptor_func_ = &JitDebug::ReadDescriptor32;
+ read_entry_func_ = &JitDebug::ReadEntry32Pack;
break;
+
case ARCH_ARM:
case ARCH_MIPS:
- static_assert(sizeof(typename JitDebugImpl32A::JITCodeEntry) == 24, "layout");
- static_assert(sizeof(typename JitDebugImpl32A::JITDescriptor) == 16, "layout");
- static_assert(sizeof(typename JitDebugImpl32A::JITDescriptorExt) == 48, "layout");
- return std::unique_ptr<JitDebug>(new JitDebugImpl32A(arch, memory, search_libs));
+ read_descriptor_func_ = &JitDebug::ReadDescriptor32;
+ read_entry_func_ = &JitDebug::ReadEntry32Pad;
break;
+
case ARCH_ARM64:
case ARCH_X86_64:
case ARCH_MIPS64:
- static_assert(sizeof(typename JitDebugImpl64A::JITCodeEntry) == 32, "layout");
- static_assert(sizeof(typename JitDebugImpl64A::JITDescriptor) == 24, "layout");
- static_assert(sizeof(typename JitDebugImpl64A::JITDescriptorExt) == 56, "layout");
- return std::unique_ptr<JitDebug>(new JitDebugImpl64A(arch, memory, search_libs));
+ read_descriptor_func_ = &JitDebug::ReadDescriptor64;
+ read_entry_func_ = &JitDebug::ReadEntry64;
break;
- default:
+ case ARCH_UNKNOWN:
abort();
}
}
-size_t JitMemory::Read(uint64_t addr, void* dst, size_t size) {
- if (!parent_->ReadFully(addr, dst, size)) {
- return 0;
- }
- // This is required for memory synchronization if the we are working with local memory.
- // For other types of memory (e.g. remote) this is no-op and has no significant effect.
- std::atomic_thread_fence(std::memory_order_acquire);
- uint32_t seen_seqlock;
- if (!parent_->Read32(seqlock_addr_, &seen_seqlock)) {
- return 0;
- }
- if (seen_seqlock != expected_seqlock_) {
- failed_due_to_race_ = true;
- return 0;
- }
- return size;
+bool JitDebug::ReadVariableData(uint64_t ptr) {
+ entry_addr_ = (this->*read_descriptor_func_)(ptr);
+ return entry_addr_ != 0;
}
-template <typename Symfile, typename PointerT, typename Uint64_T>
-bool JitDebugImpl<Symfile, PointerT, Uint64_T>::ReadVariableData(uint64_t addr) {
- JITDescriptor desc;
- if (!this->memory_->ReadFully(addr, &desc, sizeof(desc))) {
- return false;
+void JitDebug::Init(Maps* maps) {
+ if (initialized_) {
+ return;
}
- if (desc.version != 1) {
- return false;
- }
- if (desc.first_entry == 0) {
- return false; // There could be multiple descriptors. Ignore empty ones.
- }
- descriptor_addr_ = addr;
- JITDescriptorExt desc_ext;
- if (this->memory_->ReadFully(addr, &desc_ext, sizeof(desc_ext)) &&
- memcmp(desc_ext.magic, kDescriptorExtMagic, 8) == 0) {
- seqlock_addr_ = descriptor_addr_ + offsetof(JITDescriptorExt, action_seqlock);
- } else {
- // In the absence of Android-specific fields, use the head pointer instead.
- seqlock_addr_ = descriptor_addr_ + offsetof(JITDescriptor, first_entry);
- }
- return true;
+ // Regardless of what happens below, consider the init finished.
+ initialized_ = true;
+
+ FindAndReadVariable(maps, "__jit_debug_descriptor");
}
-template <typename Symfile>
-static const char* GetDescriptorName();
-
-template <>
-const char* GetDescriptorName<Elf>() {
- return "__jit_debug_descriptor";
-}
-
-template <typename Symfile, typename PointerT, typename Uint64_T>
-Symfile* JitDebugImpl<Symfile, PointerT, Uint64_T>::Get(Maps* maps, uint64_t pc) {
+Elf* JitDebug::GetElf(Maps* maps, uint64_t pc) {
+ // Use a single lock, this object should be used so infrequently that
+ // a fine grain lock is unnecessary.
std::lock_guard<std::mutex> guard(lock_);
if (!initialized_) {
- FindAndReadVariable(maps, GetDescriptorName<Symfile>());
- initialized_ = true;
+ Init(maps);
}
- if (descriptor_addr_ == 0) {
- return nullptr;
- }
-
- if (!Update(maps)) {
- return nullptr;
- }
-
- Symfile* fallback = nullptr;
- for (auto& entry : entries_) {
- // Skip entries which are obviously not relevant (if we know the PC range).
- if (entry.size_ == 0 || (entry.addr_ <= pc && (pc - entry.addr_) < entry.size_)) {
- // Double check the entry contains the PC in case there are overlapping entries.
- // This is might happen for native-code due to GC and for DEX due to data sharing.
- std::string method_name;
- uint64_t method_offset;
- if (entry.symfile_->GetFunctionName(pc, &method_name, &method_offset)) {
- return entry.symfile_.get();
- }
- fallback = entry.symfile_.get(); // Tests don't have any symbols.
- }
- }
- return fallback; // Not found.
-}
-
-// Update JIT entries if needed. It will retry if there are data races.
-template <typename Symfile, typename PointerT, typename Uint64_T>
-bool JitDebugImpl<Symfile, PointerT, Uint64_T>::Update(Maps* maps) {
- // We might need to retry the whole read in the presence of data races.
- for (int i = 0; i < kMaxRaceRetries; i++) {
- // Read the seqlock (counter which is incremented before and after any modification).
- uint32_t seqlock = 0;
- if (!this->memory_->Read32(seqlock_addr_, &seqlock)) {
- return false; // Failed to read seqlock.
- }
-
- // Check if anything changed since the last time we checked.
- if (last_seqlock_ != seqlock) {
- // Create memory wrapper to allow us to read the entries safely even in a live process.
- JitMemory safe_memory;
- safe_memory.parent_ = this->memory_.get();
- safe_memory.seqlock_addr_ = seqlock_addr_;
- safe_memory.expected_seqlock_ = seqlock;
- std::atomic_thread_fence(std::memory_order_acquire);
-
- // Add all entries to our cache.
- if (!Read(maps, &safe_memory)) {
- if (safe_memory.failed_due_to_race_) {
- sleep(0);
- continue; // Try again (there was a data race).
- } else {
- return false; // Proper failure (we could not read the data).
- }
- }
- last_seqlock_ = seqlock;
- }
- return true;
- }
- return false; // Too many retries.
-}
-
-// Read all JIT entries. It might randomly fail due to data races.
-template <typename Symfile, typename PointerT, typename Uint64_T>
-bool JitDebugImpl<Symfile, PointerT, Uint64_T>::Read(Maps* maps, JitMemory* memory) {
- std::unordered_set<uint64_t> seen_entry_addr;
-
- // Read and verify the descriptor (must be after we have read the initial seqlock).
- JITDescriptor desc;
- if (!(memory->ReadFully(descriptor_addr_, &desc, sizeof(desc)))) {
- return false;
- }
-
- entries_.clear();
- JITCodeEntry entry;
- for (uint64_t entry_addr = desc.first_entry; entry_addr != 0; entry_addr = entry.next) {
- // Check for infinite loops in the lined list.
- if (!seen_entry_addr.emplace(entry_addr).second) {
- return true; // TODO: Fail when seening infinite loop.
- }
-
- // Read the entry (while checking for data races).
- if (!memory->ReadFully(entry_addr, &entry, sizeof(entry))) {
- return false;
- }
-
- // Copy and load the symfile.
- entries_.emplace_back(JitCacheEntry<Symfile>());
- if (!entries_.back().Init(maps, memory, entry.symfile_addr, entry.symfile_size.value)) {
- return false;
+ // Search the existing elf object first.
+ for (Elf* elf : elf_list_) {
+ if (elf->IsValidPc(pc)) {
+ return elf;
}
}
- return true;
-}
+ while (entry_addr_ != 0) {
+ uint64_t start;
+ uint64_t size;
+ entry_addr_ = (this->*read_entry_func_)(&start, &size);
-// Copy and load ELF file.
-template <>
-bool JitCacheEntry<Elf>::Init(Maps*, JitMemory* memory, uint64_t addr, uint64_t size) {
- // Make a copy of the in-memory symbol file (while checking for data races).
- std::unique_ptr<MemoryBuffer> buffer(new MemoryBuffer());
- buffer->Resize(size);
- if (!memory->ReadFully(addr, buffer->GetPtr(0), buffer->Size())) {
- return false;
+ Elf* elf = new Elf(new MemoryRange(memory_, start, size, 0));
+ elf->Init();
+ if (!elf->valid()) {
+ // The data is not formatted in a way we understand, do not attempt
+ // to process any other entries.
+ entry_addr_ = 0;
+ delete elf;
+ return nullptr;
+ }
+ elf_list_.push_back(elf);
+
+ if (elf->IsValidPc(pc)) {
+ return elf;
+ }
}
-
- // Load and validate the ELF file.
- symfile_.reset(new Elf(buffer.release()));
- symfile_->Init();
- if (!symfile_->valid()) {
- return false;
- }
-
- symfile_->GetTextRange(&addr_, &size_);
- return true;
+ return nullptr;
}
-template std::unique_ptr<JitDebug<Elf>> JitDebug<Elf>::Create(ArchEnum, std::shared_ptr<Memory>&,
- std::vector<std::string>);
-
-#if !defined(NO_LIBDEXFILE_SUPPORT)
-
-template <>
-const char* GetDescriptorName<DexFile>() {
- return "__dex_debug_descriptor";
-}
-
-// Copy and load DEX file.
-template <>
-bool JitCacheEntry<DexFile>::Init(Maps* maps, JitMemory* memory, uint64_t addr, uint64_t) {
- MapInfo* info = maps->Find(addr);
- if (info == nullptr) {
- return false;
- }
- symfile_ = DexFile::Create(addr, memory, info);
- if (symfile_ == nullptr) {
- return false;
- }
- return true;
-}
-
-template std::unique_ptr<JitDebug<DexFile>> JitDebug<DexFile>::Create(ArchEnum,
- std::shared_ptr<Memory>&,
- std::vector<std::string>);
-
-#endif
-
} // namespace unwindstack
diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp
index 73c5a04..3f2e1c1 100644
--- a/libunwindstack/Unwinder.cpp
+++ b/libunwindstack/Unwinder.cpp
@@ -36,38 +36,11 @@
#include <unwindstack/Unwinder.h>
#if !defined(NO_LIBDEXFILE_SUPPORT)
-#include <DexFile.h>
+#include <unwindstack/DexFiles.h>
#endif
namespace unwindstack {
-Unwinder::Unwinder(size_t max_frames, Maps* maps, Regs* regs,
- std::shared_ptr<Memory> process_memory)
- : max_frames_(max_frames), maps_(maps), regs_(regs), process_memory_(process_memory) {
- frames_.reserve(max_frames);
- if (regs != nullptr) {
- ArchEnum arch = regs_->Arch();
-
- jit_debug_ = JitDebug<Elf>::Create(arch, process_memory_);
-#if !defined(NO_LIBDEXFILE_SUPPORT)
- dex_files_ = JitDebug<DexFile>::Create(arch, process_memory_);
-#endif
- }
-}
-
-void Unwinder::SetRegs(Regs* regs) {
- regs_ = regs;
-
- if (jit_debug_ == nullptr) {
- ArchEnum arch = regs_->Arch();
-
- jit_debug_ = JitDebug<Elf>::Create(arch, process_memory_);
-#if !defined(NO_LIBDEXFILE_SUPPORT)
- dex_files_ = JitDebug<DexFile>::Create(arch, process_memory_);
-#endif
- }
-}
-
// Inject extra 'virtual' frame that represents the dex pc data.
// The dex pc is a magic register defined in the Mterp interpreter,
// and thus it will be restored/observed in the frame after it.
@@ -111,7 +84,8 @@
return;
}
- dex_files_->GetFunctionName(maps_, dex_pc, &frame->function_name, &frame->function_offset);
+ dex_files_->GetMethodInformation(maps_, info, dex_pc, &frame->function_name,
+ &frame->function_offset);
#endif
}
@@ -211,7 +185,7 @@
// using the jit debug information.
if (!elf->valid() && jit_debug_ != nullptr) {
uint64_t adjusted_jit_pc = regs_->pc() - pc_adjustment;
- Elf* jit_elf = jit_debug_->Get(maps_, adjusted_jit_pc);
+ Elf* jit_elf = jit_debug_->GetElf(maps_, adjusted_jit_pc);
if (jit_elf != nullptr) {
// The jit debug information requires a non relative adjusted pc.
step_pc = adjusted_jit_pc;
@@ -356,7 +330,19 @@
return FormatFrame(frames_[frame_num]);
}
-bool UnwinderFromPid::Init() {
+void Unwinder::SetJitDebug(JitDebug* jit_debug, ArchEnum arch) {
+ jit_debug->SetArch(arch);
+ jit_debug_ = jit_debug;
+}
+
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+void Unwinder::SetDexFiles(DexFiles* dex_files, ArchEnum arch) {
+ dex_files->SetArch(arch);
+ dex_files_ = dex_files;
+}
+#endif
+
+bool UnwinderFromPid::Init(ArchEnum arch) {
if (pid_ == getpid()) {
maps_ptr_.reset(new LocalMaps());
} else {
@@ -369,6 +355,15 @@
process_memory_ = Memory::CreateProcessMemoryCached(pid_);
+ jit_debug_ptr_.reset(new JitDebug(process_memory_));
+ jit_debug_ = jit_debug_ptr_.get();
+ SetJitDebug(jit_debug_, arch);
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+ dex_files_ptr_.reset(new DexFiles(process_memory_));
+ dex_files_ = dex_files_ptr_.get();
+ SetDexFiles(dex_files_, arch);
+#endif
+
return true;
}
diff --git a/libunwindstack/include/unwindstack/DexFiles.h b/libunwindstack/include/unwindstack/DexFiles.h
new file mode 100644
index 0000000..67a9640
--- /dev/null
+++ b/libunwindstack/include/unwindstack/DexFiles.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2018 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 _LIBUNWINDSTACK_DEX_FILES_H
+#define _LIBUNWINDSTACK_DEX_FILES_H
+
+#include <stdint.h>
+
+#include <memory>
+#include <mutex>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include <unwindstack/Global.h>
+#include <unwindstack/Memory.h>
+
+namespace unwindstack {
+
+// Forward declarations.
+class DexFile;
+class Maps;
+struct MapInfo;
+enum ArchEnum : uint8_t;
+
+class DexFiles : public Global {
+ public:
+ explicit DexFiles(std::shared_ptr<Memory>& memory);
+ DexFiles(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs);
+ virtual ~DexFiles();
+
+ DexFile* GetDexFile(uint64_t dex_file_offset, MapInfo* info);
+
+ void GetMethodInformation(Maps* maps, MapInfo* info, uint64_t dex_pc, std::string* method_name,
+ uint64_t* method_offset);
+
+ private:
+ void Init(Maps* maps);
+
+ bool GetAddr(size_t index, uint64_t* addr);
+
+ uint64_t ReadEntryPtr32(uint64_t addr);
+
+ uint64_t ReadEntryPtr64(uint64_t addr);
+
+ bool ReadEntry32();
+
+ bool ReadEntry64();
+
+ bool ReadVariableData(uint64_t ptr_offset) override;
+
+ void ProcessArch() override;
+
+ std::mutex lock_;
+ bool initialized_ = false;
+ std::unordered_map<uint64_t, std::unique_ptr<DexFile>> files_;
+
+ uint64_t entry_addr_ = 0;
+ uint64_t (DexFiles::*read_entry_ptr_func_)(uint64_t) = nullptr;
+ bool (DexFiles::*read_entry_func_)() = nullptr;
+ std::vector<uint64_t> addrs_;
+};
+
+} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_DEX_FILES_H
diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h
index 25a665d..ac94f10 100644
--- a/libunwindstack/include/unwindstack/Elf.h
+++ b/libunwindstack/include/unwindstack/Elf.h
@@ -78,8 +78,6 @@
bool IsValidPc(uint64_t pc);
- bool GetTextRange(uint64_t* addr, uint64_t* size);
-
void GetLastError(ErrorData* data);
ErrorCode GetLastErrorCode();
uint64_t GetLastErrorAddress();
diff --git a/libunwindstack/include/unwindstack/ElfInterface.h b/libunwindstack/include/unwindstack/ElfInterface.h
index 945c277..dbd917d 100644
--- a/libunwindstack/include/unwindstack/ElfInterface.h
+++ b/libunwindstack/include/unwindstack/ElfInterface.h
@@ -68,8 +68,6 @@
virtual bool IsValidPc(uint64_t pc);
- bool GetTextRange(uint64_t* addr, uint64_t* size);
-
Memory* CreateGnuDebugdataMemory();
Memory* memory() { return memory_; }
@@ -158,9 +156,6 @@
uint64_t gnu_build_id_offset_ = 0;
uint64_t gnu_build_id_size_ = 0;
- uint64_t text_addr_ = 0;
- uint64_t text_size_ = 0;
-
uint8_t soname_type_ = SONAME_UNKNOWN;
std::string soname_;
diff --git a/libunwindstack/include/unwindstack/JitDebug.h b/libunwindstack/include/unwindstack/JitDebug.h
index 0c3ded9..8b7b4b5 100644
--- a/libunwindstack/include/unwindstack/JitDebug.h
+++ b/libunwindstack/include/unwindstack/JitDebug.h
@@ -19,7 +19,6 @@
#include <stdint.h>
-#include <map>
#include <memory>
#include <mutex>
#include <string>
@@ -31,24 +30,40 @@
namespace unwindstack {
// Forward declarations.
+class Elf;
class Maps;
enum ArchEnum : uint8_t;
-template <typename Symfile>
-class JitDebug {
+class JitDebug : public Global {
public:
- static std::unique_ptr<JitDebug> Create(ArchEnum arch, std::shared_ptr<Memory>& memory,
- std::vector<std::string> search_libs = {});
- virtual ~JitDebug() {}
+ explicit JitDebug(std::shared_ptr<Memory>& memory);
+ JitDebug(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs);
+ virtual ~JitDebug();
- // Find symbol file for given pc.
- virtual Symfile* Get(Maps* maps, uint64_t pc) = 0;
+ Elf* GetElf(Maps* maps, uint64_t pc);
- // Find symbol for given pc.
- bool GetFunctionName(Maps* maps, uint64_t pc, std::string* name, uint64_t* offset) {
- Symfile* file = Get(maps, pc);
- return file != nullptr && file->GetFunctionName(pc, name, offset);
- }
+ private:
+ void Init(Maps* maps);
+
+ uint64_t (JitDebug::*read_descriptor_func_)(uint64_t) = nullptr;
+ uint64_t (JitDebug::*read_entry_func_)(uint64_t*, uint64_t*) = nullptr;
+
+ uint64_t ReadDescriptor32(uint64_t);
+ uint64_t ReadDescriptor64(uint64_t);
+
+ uint64_t ReadEntry32Pack(uint64_t* start, uint64_t* size);
+ uint64_t ReadEntry32Pad(uint64_t* start, uint64_t* size);
+ uint64_t ReadEntry64(uint64_t* start, uint64_t* size);
+
+ bool ReadVariableData(uint64_t ptr_offset) override;
+
+ void ProcessArch() override;
+
+ uint64_t entry_addr_ = 0;
+ bool initialized_ = false;
+ std::vector<Elf*> elf_list_;
+
+ std::mutex lock_;
};
} // namespace unwindstack
diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h
index a04d7c3..8b01654 100644
--- a/libunwindstack/include/unwindstack/Unwinder.h
+++ b/libunwindstack/include/unwindstack/Unwinder.h
@@ -24,6 +24,7 @@
#include <string>
#include <vector>
+#include <unwindstack/DexFiles.h>
#include <unwindstack/Error.h>
#include <unwindstack/JitDebug.h>
#include <unwindstack/Maps.h>
@@ -33,7 +34,6 @@
namespace unwindstack {
// Forward declarations.
-class DexFile;
class Elf;
enum ArchEnum : uint8_t;
@@ -63,14 +63,14 @@
class Unwinder {
public:
- Unwinder(size_t max_frames, Maps* maps, Regs* regs, std::shared_ptr<Memory> process_memory);
+ Unwinder(size_t max_frames, Maps* maps, Regs* regs, std::shared_ptr<Memory> process_memory)
+ : max_frames_(max_frames), maps_(maps), regs_(regs), process_memory_(process_memory) {
+ frames_.reserve(max_frames);
+ }
Unwinder(size_t max_frames, Maps* maps, std::shared_ptr<Memory> process_memory)
- : Unwinder(max_frames, maps, nullptr, process_memory) {}
-
- Unwinder(const Unwinder&) = delete;
- Unwinder& operator=(const Unwinder&) = delete;
- Unwinder(Unwinder&&) = default;
- Unwinder& operator=(Unwinder&&) = default;
+ : max_frames_(max_frames), maps_(maps), process_memory_(process_memory) {
+ frames_.reserve(max_frames);
+ }
virtual ~Unwinder() = default;
@@ -90,7 +90,9 @@
std::string FormatFrame(size_t frame_num);
std::string FormatFrame(const FrameData& frame);
- void SetRegs(Regs* regs);
+ void SetJitDebug(JitDebug* jit_debug, ArchEnum arch);
+
+ void SetRegs(Regs* regs) { regs_ = regs; }
Maps* GetMaps() { return maps_; }
std::shared_ptr<Memory>& GetProcessMemory() { return process_memory_; }
@@ -105,6 +107,10 @@
void SetDisplayBuildID(bool display_build_id) { display_build_id_ = display_build_id; }
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+ void SetDexFiles(DexFiles* dex_files, ArchEnum arch);
+#endif
+
ErrorCode LastErrorCode() { return last_error_.code; }
uint64_t LastErrorAddress() { return last_error_.address; }
@@ -120,9 +126,9 @@
Regs* regs_;
std::vector<FrameData> frames_;
std::shared_ptr<Memory> process_memory_;
- std::unique_ptr<JitDebug<Elf>> jit_debug_;
+ JitDebug* jit_debug_ = nullptr;
#if !defined(NO_LIBDEXFILE_SUPPORT)
- std::unique_ptr<JitDebug<DexFile>> dex_files_;
+ DexFiles* dex_files_ = nullptr;
#endif
bool resolve_names_ = true;
bool embedded_soname_ = true;
@@ -135,11 +141,15 @@
UnwinderFromPid(size_t max_frames, pid_t pid) : Unwinder(max_frames), pid_(pid) {}
virtual ~UnwinderFromPid() = default;
- bool Init();
+ bool Init(ArchEnum arch);
private:
pid_t pid_;
std::unique_ptr<Maps> maps_ptr_;
+ std::unique_ptr<JitDebug> jit_debug_ptr_;
+#if !defined(NO_LIBDEXFILE_SUPPORT)
+ std::unique_ptr<DexFiles> dex_files_ptr_;
+#endif
};
} // namespace unwindstack
diff --git a/libunwindstack/tests/DexFileTest.cpp b/libunwindstack/tests/DexFileTest.cpp
index df7b31d..0149a42 100644
--- a/libunwindstack/tests/DexFileTest.cpp
+++ b/libunwindstack/tests/DexFileTest.cpp
@@ -177,11 +177,11 @@
std::string method;
uint64_t method_offset;
- ASSERT_TRUE(dex_file->GetFunctionName(0x4102, &method, &method_offset));
+ ASSERT_TRUE(dex_file->GetMethodInformation(0x102, &method, &method_offset));
EXPECT_EQ("Main.<init>", method);
EXPECT_EQ(2U, method_offset);
- ASSERT_TRUE(dex_file->GetFunctionName(0x4118, &method, &method_offset));
+ ASSERT_TRUE(dex_file->GetMethodInformation(0x118, &method, &method_offset));
EXPECT_EQ("Main.main", method);
EXPECT_EQ(0U, method_offset);
}
@@ -195,9 +195,9 @@
std::string method;
uint64_t method_offset;
- EXPECT_FALSE(dex_file->GetFunctionName(0x100000, &method, &method_offset));
+ EXPECT_FALSE(dex_file->GetMethodInformation(0x100000, &method, &method_offset));
- EXPECT_FALSE(dex_file->GetFunctionName(0x98, &method, &method_offset));
+ EXPECT_FALSE(dex_file->GetMethodInformation(0x98, &method, &method_offset));
}
} // namespace unwindstack
diff --git a/libunwindstack/tests/DexFilesTest.cpp b/libunwindstack/tests/DexFilesTest.cpp
index 655dcc8..1ea9e5c 100644
--- a/libunwindstack/tests/DexFilesTest.cpp
+++ b/libunwindstack/tests/DexFilesTest.cpp
@@ -22,8 +22,8 @@
#include <gtest/gtest.h>
+#include <unwindstack/DexFiles.h>
#include <unwindstack/Elf.h>
-#include <unwindstack/JitDebug.h>
#include <unwindstack/MapInfo.h>
#include <unwindstack/Maps.h>
#include <unwindstack/Memory.h>
@@ -32,10 +32,6 @@
#include "ElfFake.h"
#include "MemoryFake.h"
-#if !defined(NO_LIBDEXFILE_SUPPORT)
-#include <DexFile.h>
-#endif
-
namespace unwindstack {
class DexFilesTest : public ::testing::Test {
@@ -52,7 +48,8 @@
}
void Init(ArchEnum arch) {
- dex_files_ = JitDebug<DexFile>::Create(arch, process_memory_);
+ dex_files_.reset(new DexFiles(process_memory_));
+ dex_files_->SetArch(arch);
maps_.reset(
new BufferMaps("1000-4000 ---s 00000000 00:00 0 /fake/elf\n"
@@ -89,11 +86,10 @@
Init(ARCH_ARM);
}
- void WriteDescriptor32(uint64_t addr, uint32_t entry);
- void WriteDescriptor64(uint64_t addr, uint64_t entry);
- void WriteEntry32Pack(uint64_t addr, uint32_t next, uint32_t prev, uint32_t dex);
- void WriteEntry32Pad(uint64_t addr, uint32_t next, uint32_t prev, uint32_t dex);
- void WriteEntry64(uint64_t addr, uint64_t next, uint64_t prev, uint64_t dex);
+ void WriteDescriptor32(uint64_t addr, uint32_t head);
+ void WriteDescriptor64(uint64_t addr, uint64_t head);
+ void WriteEntry32(uint64_t entry_addr, uint32_t next, uint32_t prev, uint32_t dex_file);
+ void WriteEntry64(uint64_t entry_addr, uint64_t next, uint64_t prev, uint64_t dex_file);
void WriteDex(uint64_t dex_file);
static constexpr size_t kMapGlobalNonReadable = 2;
@@ -105,70 +101,40 @@
std::shared_ptr<Memory> process_memory_;
MemoryFake* memory_;
- std::unique_ptr<JitDebug<DexFile>> dex_files_;
+ std::unique_ptr<DexFiles> dex_files_;
std::unique_ptr<BufferMaps> maps_;
};
-void DexFilesTest::WriteDescriptor32(uint64_t addr, uint32_t entry) {
- // Format of the 32 bit JITDescriptor structure:
- // uint32_t version
- memory_->SetData32(addr, 1);
- // uint32_t action_flag
- memory_->SetData32(addr + 4, 0);
- // uint32_t relevant_entry
- memory_->SetData32(addr + 8, 0);
- // uint32_t first_entry
- memory_->SetData32(addr + 12, entry);
+void DexFilesTest::WriteDescriptor32(uint64_t addr, uint32_t head) {
+ // void* first_entry_
+ memory_->SetData32(addr + 12, head);
}
-void DexFilesTest::WriteDescriptor64(uint64_t addr, uint64_t entry) {
- // Format of the 64 bit JITDescriptor structure:
- // uint32_t version
- memory_->SetData32(addr, 1);
- // uint32_t action_flag
- memory_->SetData32(addr + 4, 0);
- // uint64_t relevant_entry
- memory_->SetData64(addr + 8, 0);
- // uint64_t first_entry
- memory_->SetData64(addr + 16, entry);
+void DexFilesTest::WriteDescriptor64(uint64_t addr, uint64_t head) {
+ // void* first_entry_
+ memory_->SetData64(addr + 16, head);
}
-void DexFilesTest::WriteEntry32Pack(uint64_t addr, uint32_t next, uint32_t prev, uint32_t dex) {
- // Format of the 32 bit JITCodeEntry structure:
+void DexFilesTest::WriteEntry32(uint64_t entry_addr, uint32_t next, uint32_t prev,
+ uint32_t dex_file) {
+ // Format of the 32 bit DEXFileEntry structure:
// uint32_t next
- memory_->SetData32(addr, next);
+ memory_->SetData32(entry_addr, next);
// uint32_t prev
- memory_->SetData32(addr + 4, prev);
- // uint32_t dex
- memory_->SetData32(addr + 8, dex);
- // uint64_t symfile_size
- memory_->SetData64(addr + 12, sizeof(kDexData) * sizeof(uint32_t));
+ memory_->SetData32(entry_addr + 4, prev);
+ // uint32_t dex_file
+ memory_->SetData32(entry_addr + 8, dex_file);
}
-void DexFilesTest::WriteEntry32Pad(uint64_t addr, uint32_t next, uint32_t prev, uint32_t dex) {
- // Format of the 32 bit JITCodeEntry structure:
- // uint32_t next
- memory_->SetData32(addr, next);
- // uint32_t prev
- memory_->SetData32(addr + 4, prev);
- // uint32_t dex
- memory_->SetData32(addr + 8, dex);
- // uint32_t pad
- memory_->SetData32(addr + 12, 0);
- // uint64_t symfile_size
- memory_->SetData64(addr + 16, sizeof(kDexData) * sizeof(uint32_t));
-}
-
-void DexFilesTest::WriteEntry64(uint64_t addr, uint64_t next, uint64_t prev, uint64_t dex) {
- // Format of the 64 bit JITCodeEntry structure:
+void DexFilesTest::WriteEntry64(uint64_t entry_addr, uint64_t next, uint64_t prev,
+ uint64_t dex_file) {
+ // Format of the 64 bit DEXFileEntry structure:
// uint64_t next
- memory_->SetData64(addr, next);
+ memory_->SetData64(entry_addr, next);
// uint64_t prev
- memory_->SetData64(addr + 8, prev);
- // uint64_t dex
- memory_->SetData64(addr + 16, dex);
- // uint64_t symfile_size
- memory_->SetData64(addr + 24, sizeof(kDexData) * sizeof(uint32_t));
+ memory_->SetData64(entry_addr + 8, prev);
+ // uint64_t dex_file
+ memory_->SetData64(entry_addr + 16, dex_file);
}
void DexFilesTest::WriteDex(uint64_t dex_file) {
@@ -178,8 +144,9 @@
TEST_F(DexFilesTest, get_method_information_invalid) {
std::string method_name = "nothing";
uint64_t method_offset = 0x124;
+ MapInfo* info = maps_->Get(kMapDexFileEntries);
- dex_files_->GetFunctionName(maps_.get(), 0, &method_name, &method_offset);
+ dex_files_->GetMethodInformation(maps_.get(), info, 0, &method_name, &method_offset);
EXPECT_EQ("nothing", method_name);
EXPECT_EQ(0x124U, method_offset);
}
@@ -187,12 +154,13 @@
TEST_F(DexFilesTest, get_method_information_32) {
std::string method_name = "nothing";
uint64_t method_offset = 0x124;
+ MapInfo* info = maps_->Get(kMapDexFiles);
WriteDescriptor32(0xf800, 0x200000);
- WriteEntry32Pad(0x200000, 0, 0, 0x300000);
+ WriteEntry32(0x200000, 0, 0, 0x300000);
WriteDex(0x300000);
- dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
+ dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
EXPECT_EQ("Main.<init>", method_name);
EXPECT_EQ(0U, method_offset);
}
@@ -202,12 +170,13 @@
std::string method_name = "nothing";
uint64_t method_offset = 0x124;
+ MapInfo* info = maps_->Get(kMapDexFiles);
WriteDescriptor64(0xf800, 0x200000);
WriteEntry64(0x200000, 0, 0, 0x301000);
WriteDex(0x301000);
- dex_files_->GetFunctionName(maps_.get(), 0x301102, &method_name, &method_offset);
+ dex_files_->GetMethodInformation(maps_.get(), info, 0x301102, &method_name, &method_offset);
EXPECT_EQ("Main.<init>", method_name);
EXPECT_EQ(2U, method_offset);
}
@@ -215,14 +184,14 @@
TEST_F(DexFilesTest, get_method_information_not_first_entry_32) {
std::string method_name = "nothing";
uint64_t method_offset = 0x124;
+ MapInfo* info = maps_->Get(kMapDexFiles);
WriteDescriptor32(0xf800, 0x200000);
- WriteEntry32Pad(0x200000, 0x200100, 0, 0x100000);
- WriteDex(0x100000);
- WriteEntry32Pad(0x200100, 0, 0x200000, 0x300000);
+ WriteEntry32(0x200000, 0x200100, 0, 0x100000);
+ WriteEntry32(0x200100, 0, 0x200000, 0x300000);
WriteDex(0x300000);
- dex_files_->GetFunctionName(maps_.get(), 0x300104, &method_name, &method_offset);
+ dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
EXPECT_EQ("Main.<init>", method_name);
EXPECT_EQ(4U, method_offset);
}
@@ -232,14 +201,14 @@
std::string method_name = "nothing";
uint64_t method_offset = 0x124;
+ MapInfo* info = maps_->Get(kMapDexFiles);
WriteDescriptor64(0xf800, 0x200000);
WriteEntry64(0x200000, 0x200100, 0, 0x100000);
- WriteDex(0x100000);
WriteEntry64(0x200100, 0, 0x200000, 0x300000);
WriteDex(0x300000);
- dex_files_->GetFunctionName(maps_.get(), 0x300106, &method_name, &method_offset);
+ dex_files_->GetMethodInformation(maps_.get(), info, 0x300106, &method_name, &method_offset);
EXPECT_EQ("Main.<init>", method_name);
EXPECT_EQ(6U, method_offset);
}
@@ -247,18 +216,19 @@
TEST_F(DexFilesTest, get_method_information_cached) {
std::string method_name = "nothing";
uint64_t method_offset = 0x124;
+ MapInfo* info = maps_->Get(kMapDexFiles);
WriteDescriptor32(0xf800, 0x200000);
- WriteEntry32Pad(0x200000, 0, 0, 0x300000);
+ WriteEntry32(0x200000, 0, 0, 0x300000);
WriteDex(0x300000);
- dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
+ dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
EXPECT_EQ("Main.<init>", method_name);
EXPECT_EQ(0U, method_offset);
// Clear all memory and make sure that data is acquired from the cache.
memory_->Clear();
- dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
+ dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
EXPECT_EQ("Main.<init>", method_name);
EXPECT_EQ(0U, method_offset);
}
@@ -266,24 +236,26 @@
TEST_F(DexFilesTest, get_method_information_search_libs) {
std::string method_name = "nothing";
uint64_t method_offset = 0x124;
+ MapInfo* info = maps_->Get(kMapDexFiles);
WriteDescriptor32(0xf800, 0x200000);
- WriteEntry32Pad(0x200000, 0x200100, 0, 0x100000);
- WriteDex(0x100000);
- WriteEntry32Pad(0x200100, 0, 0x200000, 0x300000);
+ WriteEntry32(0x200000, 0x200100, 0, 0x100000);
+ WriteEntry32(0x200100, 0, 0x200000, 0x300000);
WriteDex(0x300000);
// Only search a given named list of libs.
std::vector<std::string> libs{"libart.so"};
- dex_files_ = JitDebug<DexFile>::Create(ARCH_ARM, process_memory_, libs);
+ dex_files_.reset(new DexFiles(process_memory_, libs));
+ dex_files_->SetArch(ARCH_ARM);
- dex_files_->GetFunctionName(maps_.get(), 0x300104, &method_name, &method_offset);
+ dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
EXPECT_EQ("nothing", method_name);
EXPECT_EQ(0x124U, method_offset);
MapInfo* map_info = maps_->Get(kMapGlobal);
map_info->name = "/system/lib/libart.so";
- dex_files_ = JitDebug<DexFile>::Create(ARCH_ARM, process_memory_, libs);
+ dex_files_.reset(new DexFiles(process_memory_, libs));
+ dex_files_->SetArch(ARCH_ARM);
// Set the rw map to the same name or this will not scan this entry.
map_info = maps_->Get(kMapGlobalRw);
map_info->name = "/system/lib/libart.so";
@@ -291,7 +263,7 @@
// DexFiles object.
libs.clear();
- dex_files_->GetFunctionName(maps_.get(), 0x300104, &method_name, &method_offset);
+ dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset);
EXPECT_EQ("Main.<init>", method_name);
EXPECT_EQ(4U, method_offset);
}
@@ -299,24 +271,26 @@
TEST_F(DexFilesTest, get_method_information_global_skip_zero_32) {
std::string method_name = "nothing";
uint64_t method_offset = 0x124;
+ MapInfo* info = maps_->Get(kMapDexFiles);
// First global variable found, but value is zero.
WriteDescriptor32(0xa800, 0);
WriteDescriptor32(0xf800, 0x200000);
- WriteEntry32Pad(0x200000, 0, 0, 0x300000);
+ WriteEntry32(0x200000, 0, 0, 0x300000);
WriteDex(0x300000);
- dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
+ dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
EXPECT_EQ("Main.<init>", method_name);
EXPECT_EQ(0U, method_offset);
// Verify that second is ignored when first is set to non-zero
- dex_files_ = JitDebug<DexFile>::Create(ARCH_ARM, process_memory_);
+ dex_files_.reset(new DexFiles(process_memory_));
+ dex_files_->SetArch(ARCH_ARM);
method_name = "fail";
method_offset = 0x123;
WriteDescriptor32(0xa800, 0x100000);
- dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
+ dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
EXPECT_EQ("fail", method_name);
EXPECT_EQ(0x123U, method_offset);
}
@@ -326,6 +300,7 @@
std::string method_name = "nothing";
uint64_t method_offset = 0x124;
+ MapInfo* info = maps_->Get(kMapDexFiles);
// First global variable found, but value is zero.
WriteDescriptor64(0xa800, 0);
@@ -334,16 +309,17 @@
WriteEntry64(0x200000, 0, 0, 0x300000);
WriteDex(0x300000);
- dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
+ dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
EXPECT_EQ("Main.<init>", method_name);
EXPECT_EQ(0U, method_offset);
// Verify that second is ignored when first is set to non-zero
- dex_files_ = JitDebug<DexFile>::Create(ARCH_ARM64, process_memory_);
+ dex_files_.reset(new DexFiles(process_memory_));
+ dex_files_->SetArch(ARCH_ARM64);
method_name = "fail";
method_offset = 0x123;
WriteDescriptor64(0xa800, 0x100000);
- dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset);
+ dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset);
EXPECT_EQ("fail", method_name);
EXPECT_EQ(0x123U, method_offset);
}
diff --git a/libunwindstack/tests/ElfInterfaceTest.cpp b/libunwindstack/tests/ElfInterfaceTest.cpp
index d895863..cdc927a 100644
--- a/libunwindstack/tests/ElfInterfaceTest.cpp
+++ b/libunwindstack/tests/ElfInterfaceTest.cpp
@@ -1192,14 +1192,16 @@
char note_section[128];
Nhdr note_header = {};
note_header.n_namesz = 4; // "GNU"
- note_header.n_descsz = 8; // "BUILDID"
+ note_header.n_descsz = 7; // "BUILDID"
note_header.n_type = NT_GNU_BUILD_ID;
memcpy(¬e_section, ¬e_header, sizeof(note_header));
size_t note_offset = sizeof(note_header);
+ // The note information contains the GNU and trailing '\0'.
memcpy(¬e_section[note_offset], "GNU", sizeof("GNU"));
note_offset += sizeof("GNU");
- memcpy(¬e_section[note_offset], "BUILDID", sizeof("BUILDID"));
- note_offset += sizeof("BUILDID");
+ // This part of the note does not contain any trailing '\0'.
+ memcpy(¬e_section[note_offset], "BUILDID", 7);
+ note_offset += 8;
Shdr shdr = {};
shdr.sh_type = SHT_NOTE;
@@ -1244,24 +1246,27 @@
char note_section[128];
Nhdr note_header = {};
note_header.n_namesz = 8; // "WRONG" aligned to 4
- note_header.n_descsz = 8; // "BUILDID"
+ note_header.n_descsz = 7; // "BUILDID"
note_header.n_type = NT_GNU_BUILD_ID;
memcpy(¬e_section, ¬e_header, sizeof(note_header));
size_t note_offset = sizeof(note_header);
memcpy(¬e_section[note_offset], "WRONG", sizeof("WRONG"));
note_offset += 8;
- memcpy(¬e_section[note_offset], "BUILDID", sizeof("BUILDID"));
- note_offset += sizeof("BUILDID");
+ // This part of the note does not contain any trailing '\0'.
+ memcpy(¬e_section[note_offset], "BUILDID", 7);
+ note_offset += 8;
note_header.n_namesz = 4; // "GNU"
- note_header.n_descsz = 8; // "BUILDID"
+ note_header.n_descsz = 7; // "BUILDID"
note_header.n_type = NT_GNU_BUILD_ID;
memcpy(¬e_section[note_offset], ¬e_header, sizeof(note_header));
note_offset += sizeof(note_header);
+ // The note information contains the GNU and trailing '\0'.
memcpy(¬e_section[note_offset], "GNU", sizeof("GNU"));
note_offset += sizeof("GNU");
- memcpy(¬e_section[note_offset], "BUILDID", sizeof("BUILDID"));
- note_offset += sizeof("BUILDID");
+ // This part of the note does not contain any trailing '\0'.
+ memcpy(¬e_section[note_offset], "BUILDID", 7);
+ note_offset += 8;
Shdr shdr = {};
shdr.sh_type = SHT_NOTE;
@@ -1306,14 +1311,16 @@
char note_section[128];
Nhdr note_header = {};
note_header.n_namesz = 4; // "GNU"
- note_header.n_descsz = 8; // "BUILDID"
+ note_header.n_descsz = 7; // "BUILDID"
note_header.n_type = NT_GNU_BUILD_ID;
memcpy(¬e_section, ¬e_header, sizeof(note_header));
size_t note_offset = sizeof(note_header);
+ // The note information contains the GNU and trailing '\0'.
memcpy(¬e_section[note_offset], "GNU", sizeof("GNU"));
note_offset += sizeof("GNU");
- memcpy(¬e_section[note_offset], "BUILDID", sizeof("BUILDID"));
- note_offset += sizeof("BUILDID");
+ // This part of the note does not contain any trailing '\0'.
+ memcpy(¬e_section[note_offset], "BUILDID", 7);
+ note_offset += 8;
Shdr shdr = {};
shdr.sh_type = SHT_NOTE;
@@ -1358,14 +1365,16 @@
char note_section[128];
Nhdr note_header = {};
note_header.n_namesz = 4; // "GNU"
- note_header.n_descsz = 8; // "BUILDID"
+ note_header.n_descsz = 7; // "BUILDID"
note_header.n_type = NT_GNU_BUILD_ID;
memcpy(¬e_section, ¬e_header, sizeof(note_header));
size_t note_offset = sizeof(note_header);
+ // The note information contains the GNU and trailing '\0'.
memcpy(¬e_section[note_offset], "GNU", sizeof("GNU"));
note_offset += sizeof("GNU");
- memcpy(¬e_section[note_offset], "BUILDID", sizeof("BUILDID"));
- note_offset += sizeof("BUILDID");
+ // This part of the note does not contain any trailing '\0'.
+ memcpy(¬e_section[note_offset], "BUILDID", 7);
+ note_offset += 8;
Shdr shdr = {};
shdr.sh_type = SHT_NOTE;
@@ -1410,14 +1419,16 @@
char note_section[128];
Nhdr note_header = {};
note_header.n_namesz = 4; // "GNU"
- note_header.n_descsz = 8; // "BUILDID"
+ note_header.n_descsz = 7; // "BUILDID"
note_header.n_type = NT_GNU_BUILD_ID;
memcpy(¬e_section, ¬e_header, sizeof(note_header));
size_t note_offset = sizeof(note_header);
+ // The note information contains the GNU and trailing '\0'.
memcpy(¬e_section[note_offset], "GNU", sizeof("GNU"));
note_offset += sizeof("GNU");
- memcpy(¬e_section[note_offset], "BUILDID", sizeof("BUILDID"));
- note_offset += sizeof("BUILDID");
+ // This part of the note does not contain any trailing '\0'.
+ memcpy(¬e_section[note_offset], "BUILDID", 7);
+ note_offset += 8;
Shdr shdr = {};
shdr.sh_type = SHT_NOTE;
diff --git a/libunwindstack/tests/JitDebugTest.cpp b/libunwindstack/tests/JitDebugTest.cpp
index 438194a..b1ca111 100644
--- a/libunwindstack/tests/JitDebugTest.cpp
+++ b/libunwindstack/tests/JitDebugTest.cpp
@@ -46,7 +46,8 @@
}
void Init(ArchEnum arch) {
- jit_debug_ = JitDebug<Elf>::Create(arch, process_memory_);
+ jit_debug_.reset(new JitDebug(process_memory_));
+ jit_debug_->SetArch(arch);
maps_.reset(
new BufferMaps("1000-4000 ---s 00000000 00:00 0 /fake/elf1\n"
@@ -61,12 +62,6 @@
"200000-210000 rw-p 0002000 00:00 0 /fake/elf4\n"));
ASSERT_TRUE(maps_->Parse());
- // Ensure all memory of the ELF file is initialized,
- // otherwise reads within it may fail.
- for (uint64_t addr = 0x4000; addr < 0x6000; addr += 8) {
- memory_->SetData64(addr, 0);
- }
-
MapInfo* map_info = maps_->Get(3);
ASSERT_TRUE(map_info != nullptr);
CreateFakeElf(map_info);
@@ -99,7 +94,7 @@
ehdr.e_shstrndx = 1;
ehdr.e_shoff = sh_offset;
ehdr.e_shentsize = sizeof(ShdrType);
- ehdr.e_shnum = 4;
+ ehdr.e_shnum = 3;
memory_->SetMemory(offset, &ehdr, sizeof(ehdr));
ShdrType shdr;
@@ -115,7 +110,6 @@
shdr.sh_size = 0x100;
memory_->SetMemory(offset + sh_offset, &shdr, sizeof(shdr));
memory_->SetMemory(offset + 0x500, ".debug_frame");
- memory_->SetMemory(offset + 0x550, ".text");
sh_offset += sizeof(shdr);
memset(&shdr, 0, sizeof(shdr));
@@ -126,15 +120,6 @@
shdr.sh_size = 0x200;
memory_->SetMemory(offset + sh_offset, &shdr, sizeof(shdr));
- sh_offset += sizeof(shdr);
- memset(&shdr, 0, sizeof(shdr));
- shdr.sh_type = SHT_NOBITS;
- shdr.sh_name = 0x50;
- shdr.sh_addr = pc;
- shdr.sh_offset = 0;
- shdr.sh_size = size;
- memory_->SetMemory(offset + sh_offset, &shdr, sizeof(shdr));
-
// Now add a single cie/fde.
uint64_t dwarf_offset = offset + 0x600;
if (class_type == ELFCLASS32) {
@@ -183,7 +168,7 @@
std::shared_ptr<Memory> process_memory_;
MemoryFake* memory_;
- std::unique_ptr<JitDebug<Elf>> jit_debug_;
+ std::unique_ptr<JitDebug> jit_debug_;
std::unique_ptr<BufferMaps> maps_;
};
@@ -253,20 +238,20 @@
}
TEST_F(JitDebugTest, get_elf_invalid) {
- Elf* elf = jit_debug_->Get(maps_.get(), 0x1500);
+ Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
ASSERT_TRUE(elf == nullptr);
}
TEST_F(JitDebugTest, get_elf_no_global_variable) {
maps_.reset(new BufferMaps(""));
- Elf* elf = jit_debug_->Get(maps_.get(), 0x1500);
+ Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
ASSERT_TRUE(elf == nullptr);
}
TEST_F(JitDebugTest, get_elf_no_valid_descriptor_in_memory) {
CreateElf<Elf32_Ehdr, Elf32_Shdr>(0x4000, ELFCLASS32, EM_ARM, 0x1500, 0x200);
- Elf* elf = jit_debug_->Get(maps_.get(), 0x1500);
+ Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
ASSERT_TRUE(elf == nullptr);
}
@@ -275,7 +260,7 @@
WriteDescriptor32(0xf800, 0x200000);
- Elf* elf = jit_debug_->Get(maps_.get(), 0x1500);
+ Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
ASSERT_TRUE(elf == nullptr);
}
@@ -284,7 +269,7 @@
WriteDescriptor32(0xf800, 0);
- Elf* elf = jit_debug_->Get(maps_.get(), 0x1500);
+ Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
ASSERT_TRUE(elf == nullptr);
}
@@ -295,7 +280,7 @@
// Set the version to an invalid value.
memory_->SetData32(0xf800, 2);
- Elf* elf = jit_debug_->Get(maps_.get(), 0x1500);
+ Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
ASSERT_TRUE(elf == nullptr);
}
@@ -305,18 +290,12 @@
WriteDescriptor32(0xf800, 0x200000);
WriteEntry32Pad(0x200000, 0, 0, 0x4000, 0x1000);
- Elf* elf = jit_debug_->Get(maps_.get(), 0x1500);
+ Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
ASSERT_TRUE(elf != nullptr);
- uint64_t text_addr;
- uint64_t text_size;
- ASSERT_TRUE(elf->GetTextRange(&text_addr, &text_size));
- ASSERT_EQ(text_addr, 0x1500u);
- ASSERT_EQ(text_size, 0x200u);
// Clear the memory and verify all of the data is cached.
memory_->Clear();
- WriteDescriptor32(0xf800, 0x200000);
- Elf* elf2 = jit_debug_->Get(maps_.get(), 0x1500);
+ Elf* elf2 = jit_debug_->GetElf(maps_.get(), 0x1500);
ASSERT_TRUE(elf2 != nullptr);
EXPECT_EQ(elf, elf2);
}
@@ -330,15 +309,16 @@
WriteDescriptor32(0x12800, 0x201000);
WriteEntry32Pad(0x201000, 0, 0, 0x5000, 0x1000);
- ASSERT_TRUE(jit_debug_->Get(maps_.get(), 0x1500) != nullptr);
- ASSERT_TRUE(jit_debug_->Get(maps_.get(), 0x2000) == nullptr);
+ ASSERT_TRUE(jit_debug_->GetElf(maps_.get(), 0x1500) != nullptr);
+ ASSERT_TRUE(jit_debug_->GetElf(maps_.get(), 0x2000) == nullptr);
// Now clear the descriptor entry for the first one.
WriteDescriptor32(0xf800, 0);
- jit_debug_ = JitDebug<Elf>::Create(ARCH_ARM, process_memory_);
+ jit_debug_.reset(new JitDebug(process_memory_));
+ jit_debug_->SetArch(ARCH_ARM);
- ASSERT_TRUE(jit_debug_->Get(maps_.get(), 0x1500) == nullptr);
- ASSERT_TRUE(jit_debug_->Get(maps_.get(), 0x2000) != nullptr);
+ ASSERT_TRUE(jit_debug_->GetElf(maps_.get(), 0x1500) == nullptr);
+ ASSERT_TRUE(jit_debug_->GetElf(maps_.get(), 0x2000) != nullptr);
}
TEST_F(JitDebugTest, get_elf_x86) {
@@ -349,14 +329,13 @@
WriteDescriptor32(0xf800, 0x200000);
WriteEntry32Pack(0x200000, 0, 0, 0x4000, 0x1000);
- jit_debug_ = JitDebug<Elf>::Create(ARCH_X86, process_memory_);
- Elf* elf = jit_debug_->Get(maps_.get(), 0x1500);
+ jit_debug_->SetArch(ARCH_X86);
+ Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
ASSERT_TRUE(elf != nullptr);
// Clear the memory and verify all of the data is cached.
memory_->Clear();
- WriteDescriptor32(0xf800, 0x200000);
- Elf* elf2 = jit_debug_->Get(maps_.get(), 0x1500);
+ Elf* elf2 = jit_debug_->GetElf(maps_.get(), 0x1500);
ASSERT_TRUE(elf2 != nullptr);
EXPECT_EQ(elf, elf2);
}
@@ -369,13 +348,12 @@
WriteDescriptor64(0xf800, 0x200000);
WriteEntry64(0x200000, 0, 0, 0x4000, 0x1000);
- Elf* elf = jit_debug_->Get(maps_.get(), 0x1500);
+ Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500);
ASSERT_TRUE(elf != nullptr);
// Clear the memory and verify all of the data is cached.
memory_->Clear();
- WriteDescriptor64(0xf800, 0x200000);
- Elf* elf2 = jit_debug_->Get(maps_.get(), 0x1500);
+ Elf* elf2 = jit_debug_->GetElf(maps_.get(), 0x1500);
ASSERT_TRUE(elf2 != nullptr);
EXPECT_EQ(elf, elf2);
}
@@ -388,21 +366,20 @@
WriteEntry32Pad(0x200000, 0, 0x200100, 0x4000, 0x1000);
WriteEntry32Pad(0x200100, 0x200100, 0, 0x5000, 0x1000);
- Elf* elf_2 = jit_debug_->Get(maps_.get(), 0x2400);
+ Elf* elf_2 = jit_debug_->GetElf(maps_.get(), 0x2400);
ASSERT_TRUE(elf_2 != nullptr);
- Elf* elf_1 = jit_debug_->Get(maps_.get(), 0x1600);
+ Elf* elf_1 = jit_debug_->GetElf(maps_.get(), 0x1600);
ASSERT_TRUE(elf_1 != nullptr);
// Clear the memory and verify all of the data is cached.
memory_->Clear();
- WriteDescriptor32(0xf800, 0x200000);
- EXPECT_EQ(elf_1, jit_debug_->Get(maps_.get(), 0x1500));
- EXPECT_EQ(elf_1, jit_debug_->Get(maps_.get(), 0x16ff));
- EXPECT_EQ(elf_2, jit_debug_->Get(maps_.get(), 0x2300));
- EXPECT_EQ(elf_2, jit_debug_->Get(maps_.get(), 0x26ff));
- EXPECT_EQ(nullptr, jit_debug_->Get(maps_.get(), 0x1700));
- EXPECT_EQ(nullptr, jit_debug_->Get(maps_.get(), 0x2700));
+ EXPECT_EQ(elf_1, jit_debug_->GetElf(maps_.get(), 0x1500));
+ EXPECT_EQ(elf_1, jit_debug_->GetElf(maps_.get(), 0x16ff));
+ EXPECT_EQ(elf_2, jit_debug_->GetElf(maps_.get(), 0x2300));
+ EXPECT_EQ(elf_2, jit_debug_->GetElf(maps_.get(), 0x26ff));
+ EXPECT_EQ(nullptr, jit_debug_->GetElf(maps_.get(), 0x1700));
+ EXPECT_EQ(nullptr, jit_debug_->GetElf(maps_.get(), 0x2700));
}
TEST_F(JitDebugTest, get_elf_search_libs) {
@@ -413,19 +390,21 @@
// Only search a given named list of libs.
std::vector<std::string> libs{"libart.so"};
- jit_debug_ = JitDebug<Elf>::Create(ARCH_ARM, process_memory_, libs);
- EXPECT_TRUE(jit_debug_->Get(maps_.get(), 0x1500) == nullptr);
+ jit_debug_.reset(new JitDebug(process_memory_, libs));
+ jit_debug_->SetArch(ARCH_ARM);
+ EXPECT_TRUE(jit_debug_->GetElf(maps_.get(), 0x1500) == nullptr);
// Change the name of the map that includes the value and verify this works.
MapInfo* map_info = maps_->Get(5);
map_info->name = "/system/lib/libart.so";
map_info = maps_->Get(6);
map_info->name = "/system/lib/libart.so";
- jit_debug_ = JitDebug<Elf>::Create(ARCH_ARM, process_memory_);
+ jit_debug_.reset(new JitDebug(process_memory_, libs));
// Make sure that clearing our copy of the libs doesn't affect the
// JitDebug object.
libs.clear();
- EXPECT_TRUE(jit_debug_->Get(maps_.get(), 0x1500) != nullptr);
+ jit_debug_->SetArch(ARCH_ARM);
+ EXPECT_TRUE(jit_debug_->GetElf(maps_.get(), 0x1500) != nullptr);
}
} // namespace unwindstack
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index 0867561..02ba9c8 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -204,6 +204,7 @@
TEST_F(UnwindOfflineTest, pc_straddle_arm) {
ASSERT_NO_FATAL_FAILURE(Init("straddle_arm/", ARCH_ARM));
+ std::unique_ptr<Regs> regs_copy(regs_->Clone());
Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
unwinder.Unwind();
@@ -223,6 +224,22 @@
EXPECT_EQ(0xe9c86730U, unwinder.frames()[2].sp);
EXPECT_EQ(0xf3367147U, unwinder.frames()[3].pc);
EXPECT_EQ(0xe9c86778U, unwinder.frames()[3].sp);
+
+ // Display build ids now.
+ unwinder.SetRegs(regs_copy.get());
+ unwinder.SetDisplayBuildID(true);
+ unwinder.Unwind();
+
+ frame_info = DumpFrames(unwinder);
+ ASSERT_EQ(4U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
+ EXPECT_EQ(
+ " #00 pc 0001a9f8 libc.so (abort+64) (BuildId: 2dd0d4ba881322a0edabeed94808048c)\n"
+ " #01 pc 00006a1b libbase.so (android::base::DefaultAborter(char const*)+6) (BuildId: "
+ "ed43842c239cac1a618e600ea91c4cbd)\n"
+ " #02 pc 00007441 libbase.so (android::base::LogMessage::~LogMessage()+748) (BuildId: "
+ "ed43842c239cac1a618e600ea91c4cbd)\n"
+ " #03 pc 00015147 /does/not/exist/libhidlbase.so\n",
+ frame_info);
}
TEST_F(UnwindOfflineTest, pc_in_gnu_debugdata_arm) {
@@ -290,7 +307,9 @@
}
process_memory_.reset(memory);
+ JitDebug jit_debug(process_memory_);
Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
+ unwinder.SetJitDebug(&jit_debug, regs_->Arch());
unwinder.Unwind();
std::string frame_info(DumpFrames(unwinder));
@@ -590,7 +609,9 @@
}
process_memory_.reset(memory);
+ JitDebug jit_debug(process_memory_);
Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
+ unwinder.SetJitDebug(&jit_debug, regs_->Arch());
unwinder.Unwind();
std::string frame_info(DumpFrames(unwinder));
@@ -911,7 +932,9 @@
LeakType* leak_data = reinterpret_cast<LeakType*>(data);
std::unique_ptr<Regs> regs_copy(leak_data->regs->Clone());
+ JitDebug jit_debug(leak_data->process_memory);
Unwinder unwinder(128, leak_data->maps, regs_copy.get(), leak_data->process_memory);
+ unwinder.SetJitDebug(&jit_debug, regs_copy->Arch());
unwinder.Unwind();
ASSERT_EQ(76U, unwinder.NumFrames());
}
@@ -1032,7 +1055,9 @@
}
process_memory_.reset(memory);
+ JitDebug jit_debug(process_memory_);
Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
+ unwinder.SetJitDebug(&jit_debug, regs_->Arch());
unwinder.Unwind();
std::string frame_info(DumpFrames(unwinder));
diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp
index 5e7e6bf..4e38015 100644
--- a/libunwindstack/tests/UnwindTest.cpp
+++ b/libunwindstack/tests/UnwindTest.cpp
@@ -170,7 +170,7 @@
unwinder.reset(new Unwinder(512, maps.get(), regs.get(), process_memory));
} else {
UnwinderFromPid* unwinder_from_pid = new UnwinderFromPid(512, getpid());
- ASSERT_TRUE(unwinder_from_pid->Init());
+ ASSERT_TRUE(unwinder_from_pid->Init(regs->Arch()));
unwinder_from_pid->SetRegs(regs.get());
unwinder.reset(unwinder_from_pid);
}
@@ -283,7 +283,7 @@
ASSERT_TRUE(regs.get() != nullptr);
UnwinderFromPid unwinder(512, pid);
- ASSERT_TRUE(unwinder.Init());
+ ASSERT_TRUE(unwinder.Init(regs->Arch()));
unwinder.SetRegs(regs.get());
VerifyUnwind(&unwinder, kFunctionOrder);
@@ -335,7 +335,7 @@
ASSERT_TRUE(regs.get() != nullptr);
UnwinderFromPid unwinder(512, *pid);
- ASSERT_TRUE(unwinder.Init());
+ ASSERT_TRUE(unwinder.Init(regs->Arch()));
unwinder.SetRegs(regs.get());
VerifyUnwind(&unwinder, kFunctionOrder);
diff --git a/libunwindstack/tools/unwind.cpp b/libunwindstack/tools/unwind.cpp
index cad95f8..1812e50 100644
--- a/libunwindstack/tools/unwind.cpp
+++ b/libunwindstack/tools/unwind.cpp
@@ -26,6 +26,7 @@
#include <sys/types.h>
#include <unistd.h>
+#include <unwindstack/DexFiles.h>
#include <unwindstack/Elf.h>
#include <unwindstack/JitDebug.h>
#include <unwindstack/Maps.h>
@@ -89,7 +90,7 @@
printf("\n");
unwindstack::UnwinderFromPid unwinder(1024, pid);
- if (!unwinder.Init()) {
+ if (!unwinder.Init(regs->Arch())) {
printf("Failed to init unwinder object.\n");
return;
}
diff --git a/libunwindstack/tools/unwind_for_offline.cpp b/libunwindstack/tools/unwind_for_offline.cpp
index 86f3163..4f67d67 100644
--- a/libunwindstack/tools/unwind_for_offline.cpp
+++ b/libunwindstack/tools/unwind_for_offline.cpp
@@ -248,7 +248,7 @@
// Do an unwind so we know how much of the stack to save, and what
// elf files are involved.
unwindstack::UnwinderFromPid unwinder(1024, pid);
- if (!unwinder.Init()) {
+ if (!unwinder.Init(regs->Arch())) {
printf("Unable to init unwinder object.\n");
return 1;
}
diff --git a/logd/Android.bp b/logd/Android.bp
index 360f2fe..9b86258 100644
--- a/logd/Android.bp
+++ b/logd/Android.bp
@@ -80,6 +80,24 @@
cflags: ["-Werror"],
}
+cc_binary {
+ name: "auditctl",
+
+ srcs: ["auditctl.cpp"],
+
+ static_libs: [
+ "liblogd",
+ ],
+
+ shared_libs: ["libbase"],
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-Wconversion"
+ ],
+}
prebuilt_etc {
name: "logtagd.rc",
diff --git a/logd/auditctl.cpp b/logd/auditctl.cpp
new file mode 100644
index 0000000..98bb02d
--- /dev/null
+++ b/logd/auditctl.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2019 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 <android-base/parseint.h>
+#include <error.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "libaudit.h"
+
+static void usage(const char* cmdline) {
+ fprintf(stderr, "Usage: %s [-r rate]\n", cmdline);
+}
+
+static void do_update_rate(uint32_t rate) {
+ int fd = audit_open();
+ if (fd == -1) {
+ error(EXIT_FAILURE, errno, "Unable to open audit socket");
+ }
+ int result = audit_rate_limit(fd, rate);
+ close(fd);
+ if (result < 0) {
+ fprintf(stderr, "Can't update audit rate limit: %d\n", result);
+ exit(EXIT_FAILURE);
+ }
+}
+
+int main(int argc, char* argv[]) {
+ uint32_t rate = 0;
+ bool update_rate = false;
+ int opt;
+
+ while ((opt = getopt(argc, argv, "r:")) != -1) {
+ switch (opt) {
+ case 'r':
+ if (!android::base::ParseUint<uint32_t>(optarg, &rate)) {
+ error(EXIT_FAILURE, errno, "Invalid Rate");
+ }
+ update_rate = true;
+ break;
+ default: /* '?' */
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ // In the future, we may add other options to auditctl
+ // so this if statement will expand.
+ // if (!update_rate && !update_backlog && !update_whatever) ...
+ if (!update_rate) {
+ fprintf(stderr, "Nothing to do\n");
+ usage(argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ if (update_rate) {
+ do_update_rate(rate);
+ }
+
+ return 0;
+}
diff --git a/logd/libaudit.c b/logd/libaudit.c
index 9d9a857..f452c71 100644
--- a/logd/libaudit.c
+++ b/logd/libaudit.c
@@ -160,8 +160,7 @@
* and the the mask set to AUDIT_STATUS_PID
*/
status.pid = pid;
- status.mask = AUDIT_STATUS_PID | AUDIT_STATUS_RATE_LIMIT;
- status.rate_limit = AUDIT_RATE_LIMIT; /* audit entries per second */
+ status.mask = AUDIT_STATUS_PID;
/* Let the kernel know this pid will be registering for audit events */
rc = audit_send(fd, AUDIT_SET, &status, sizeof(status));
@@ -188,6 +187,14 @@
return socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_AUDIT);
}
+int audit_rate_limit(int fd, uint32_t limit) {
+ struct audit_status status;
+ memset(&status, 0, sizeof(status));
+ status.mask = AUDIT_STATUS_RATE_LIMIT;
+ status.rate_limit = limit; /* audit entries per second */
+ return audit_send(fd, AUDIT_SET, &status, sizeof(status));
+}
+
int audit_get_reply(int fd, struct audit_message* rep, reply_t block, int peek) {
ssize_t len;
int flags;
diff --git a/logd/libaudit.h b/logd/libaudit.h
index 2a93ea3..b4a92a8 100644
--- a/logd/libaudit.h
+++ b/logd/libaudit.h
@@ -89,8 +89,17 @@
*/
extern int audit_setup(int fd, pid_t pid);
-/* Max audit messages per second */
-#define AUDIT_RATE_LIMIT 5
+/**
+ * Throttle kernel messages at the provided rate
+ * @param fd
+ * The fd returned by a call to audit_open()
+ * @param rate
+ * The rate, in messages per second, above which the kernel
+ * should drop audit messages.
+ * @return
+ * This function returns 0 on success, -errno on error.
+ */
+extern int audit_rate_limit(int fd, uint32_t limit);
__END_DECLS
diff --git a/logd/logd.rc b/logd/logd.rc
index c740ecf..438419a 100644
--- a/logd/logd.rc
+++ b/logd/logd.rc
@@ -16,8 +16,19 @@
group logd
writepid /dev/cpuset/system-background/tasks
+# Limit SELinux denial generation to 5/second
+service logd-auditctl /system/bin/auditctl -r 5
+ oneshot
+ disabled
+ user logd
+ group logd
+ capabilities AUDIT_CONTROL
+
on fs
write /dev/event-log-tags "# content owned by logd
"
chown logd logd /dev/event-log-tags
chmod 0644 /dev/event-log-tags
+
+on property:sys.boot_completed=1
+ start logd-auditctl
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
index 7d7a22f..447b067 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -39,7 +39,6 @@
#endif
#include "../LogReader.h" // pickup LOGD_SNDTIMEO
-#include "../libaudit.h" // pickup AUDIT_RATE_LIMIT_*
#ifdef __ANDROID__
static void send_to_control(char* buf, size_t len) {
@@ -1065,145 +1064,3 @@
TEST(logd, multiple_test_10) {
__android_log_btwrite_multiple__helper(10);
}
-
-#ifdef __ANDROID__
-// returns violating pid
-static pid_t sepolicy_rate(unsigned rate, unsigned num) {
- pid_t pid = fork();
-
- if (pid) {
- siginfo_t info = {};
- if (TEMP_FAILURE_RETRY(waitid(P_PID, pid, &info, WEXITED))) return -1;
- if (info.si_status) return -1;
- return pid;
- }
-
- // We may have DAC, but let's not have MAC
- if ((setcon("u:object_r:shell:s0") < 0) && (setcon("u:r:shell:s0") < 0)) {
- int save_errno = errno;
- security_context_t context;
- getcon(&context);
- if (strcmp(context, "u:r:shell:s0")) {
- fprintf(stderr, "setcon(\"u:r:shell:s0\") failed @\"%s\" %s\n",
- context, strerror(save_errno));
- freecon(context);
- _exit(-1);
- // NOTREACHED
- return -1;
- }
- }
-
- // The key here is we are root, but we are in u:r:shell:s0,
- // and the directory does not provide us DAC access
- // (eg: 0700 system system) so we trigger the pair dac_override
- // and dac_read_search on every try to get past the message
- // de-duper. We will also rotate the file name in the directory
- // as another measure.
- static const char file[] = "/data/drm/cannot_access_directory_%u";
- static const unsigned avc_requests_per_access = 2;
-
- rate /= avc_requests_per_access;
- useconds_t usec;
- if (rate == 0) {
- rate = 1;
- usec = 2000000;
- } else {
- usec = (1000000 + (rate / 2)) / rate;
- }
- num = (num + (avc_requests_per_access / 2)) / avc_requests_per_access;
-
- if (usec < 2) usec = 2;
-
- while (num > 0) {
- if (access(android::base::StringPrintf(file, num).c_str(), F_OK) == 0) {
- _exit(-1);
- // NOTREACHED
- return -1;
- }
- usleep(usec);
- --num;
- }
- _exit(0);
- // NOTREACHED
- return -1;
-}
-
-static constexpr int background_period = 10;
-
-static int count_avc(pid_t pid) {
- int count = 0;
-
- // pid=-1 skip as pid is in error
- if (pid == (pid_t)-1) return count;
-
- // pid=0 means we want to report the background count of avc: activities
- struct logger_list* logger_list =
- pid ? android_logger_list_alloc(
- ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 0, pid)
- : android_logger_list_alloc_time(
- ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK,
- log_time(android_log_clockid()) -
- log_time(background_period, 0),
- 0);
- if (!logger_list) return count;
- struct logger* logger = android_logger_open(logger_list, LOG_ID_EVENTS);
- if (!logger) {
- android_logger_list_close(logger_list);
- return count;
- }
- for (;;) {
- log_msg log_msg;
-
- if (android_logger_list_read(logger_list, &log_msg) <= 0) break;
-
- if ((log_msg.entry.pid != pid) || (log_msg.entry.len < (4 + 1 + 8)) ||
- (log_msg.id() != LOG_ID_EVENTS))
- continue;
-
- char* eventData = log_msg.msg();
- if (!eventData) continue;
-
- uint32_t tag = get4LE(eventData);
- if (tag != AUDITD_LOG_TAG) continue;
-
- if (eventData[4] != EVENT_TYPE_STRING) continue;
-
- // int len = get4LE(eventData + 4 + 1);
- log_msg.buf[LOGGER_ENTRY_MAX_LEN] = '\0';
- const char* cp = strstr(eventData + 4 + 1 + 4, "): avc: denied");
- if (!cp) continue;
-
- ++count;
- }
-
- android_logger_list_close(logger_list);
-
- return count;
-}
-#endif
-
-TEST(logd, sepolicy_rate_limiter) {
-#ifdef __ANDROID__
- int background_selinux_activity_too_high = count_avc(0);
- if (background_selinux_activity_too_high > 2) {
- GTEST_LOG_(ERROR) << "Too much background selinux activity "
- << background_selinux_activity_too_high * 60 /
- background_period
- << "/minute on the device, this test\n"
- << "can not measure the functionality of the "
- << "sepolicy rate limiter. Expect test to\n"
- << "fail as this device is in a bad state, "
- << "but is not strictly a unit test failure.";
- }
-
- static const int rate = AUDIT_RATE_LIMIT;
- static const int duration = 2;
- // Two seconds of sustained denials. Depending on the overlap in the time
- // window that the kernel is considering vs what this test is considering,
- // allow some additional denials to prevent a flaky test.
- EXPECT_LE(count_avc(sepolicy_rate(rate, rate * duration)),
- rate * duration + rate);
-#else
- GTEST_LOG_(INFO) << "This test does nothing.\n";
-#endif
-}
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 75035d0..b274cf3 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -280,6 +280,11 @@
write /dev/cpu_variant:${ro.bionic.2nd_arch} ${ro.bionic.2nd_cpu_variant}
chmod 0444 /dev/cpu_variant:${ro.bionic.2nd_arch}
+ # Allow system processes to read / write power state.
+ chown system system /sys/power/state
+ chown system system /sys/power/wakeup_count
+ chmod 0660 /sys/power/state
+
# Start logd before any other services run to ensure we capture all of their logs.
start logd
@@ -671,11 +676,8 @@
chown radio system /sys/android_power/acquire_partial_wake_lock
chown radio system /sys/android_power/release_wake_lock
chown system system /sys/power/autosleep
- chown system system /sys/power/state
- chown system system /sys/power/wakeup_count
chown radio wakelock /sys/power/wake_lock
chown radio wakelock /sys/power/wake_unlock
- chmod 0660 /sys/power/state
chmod 0660 /sys/power/wake_lock
chmod 0660 /sys/power/wake_unlock
diff --git a/shell_and_utilities/Android.bp b/shell_and_utilities/Android.bp
index f01a8c7..3bc3883 100644
--- a/shell_and_utilities/Android.bp
+++ b/shell_and_utilities/Android.bp
@@ -10,6 +10,7 @@
phony {
name: "shell_and_utilities_system",
required: [
+ "auditctl",
"awk",
"bzip2",
"grep",